eolas/neuron/8a3d2c22-db18-478e-8e4c-1e11b6fe5320/React_useReducer.md

134 lines
3.1 KiB
Markdown
Raw Normal View History

2024-11-17 15:37:31 +00:00
---
tags:
- javascript
- react
---
# `useReducer`
The `useReducer` hook is best used in scenarios where you are manipulating state
in a way that is too complex for the trivial [React_useState](React_useState.md) use case.
`useState` is best employed when you are updating a single value or toggling a
boolean. If you are updating the state of an object or more complex data
structure, it is often more efficient to employ `useReducer`.
This makes the code more manageable and also helps with separating state
management from rendering.
## Syntax
```jsx
const [state, dispatch] = useReducer(reducer, initialState);
```
- `initialState`
- The starting state, typically an object
- `reducer`
- A pure function that accepts two parameters:
- The current state
- An action object
- The reducer function must update the current state (immutably) and return
the new state
- We can think of the reducer as working in the same manner as
`state`/`setState` in the `useState` hook. The functional role is the same,
it is just that the reducer offers more than one type of update.
### Example reducer
```js
function reducer(state, action) {
let newState;
switch (action.type) {
case "increase":
newState = { counter: state.counter + 1 };
break;
case "descrease":
newState = { counter: state.counter - 1 };
break;
default:
throw new Error();
}
return newState;
}
```
In this example we are updating an object with the following shape:
```js
{
counter: 0,
}
```
This would be the `initialState` that we pass to the `useReducer` hook along
with a reference to `reducer` above.
To update the state we would invoke the `dispatch` function which applies one of
the actions defined in the reducer. For example the following dispatch
increments the counter by one:
```js
dispatch({ type: "increase" });
```
To view the updated value:
```js
console.log(state.counter);
```
### Refining the syntax
Because React doesn't mutate state, the reducer doesn't directly modify the
current state in the `state` variable, it creates a new instance of the state
object on each update.
In the reducer example above this is achieved by declaring a variable `newState`
that is updated by each `action` type and then returned. There is a more elegant
way of doing this using spread syntax:
```js
function reducer(state, action) {
switch (action.type) {
case "increase":
return { ...state, counter: state.counter + 1 };
break;
case "decrease":
return { ...state, counter: state.counter - 1 };
break;
default:
throw new Error();
}
}
```
### Including payloads
In the examples so far, we have updated the the state directly via the action
type however it is also possible to pass data along with the `action.type` as
`action.payload`.
For example:
```js
dispatch(
{
type: 'increase_by_payload'
payload: 3,
});
```
Then we would update our reducer to handle this case:
```js
function reducer(state, action) {
switch (action.type) {
...
case 'increase_by_payload':
return {...state, counter: state.counter + action.payload}
default:
throw new Error();
}
}
```