You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This might look strange at first, but an update during rendering is exactly what `getDerivedStateFromProps` has always been like conceptually.
324
325
326
+
### Is there something like forceUpdate?
327
+
328
+
Both `useState` and `useReducer` Hooks [bail out of updates](/docs/hooks-reference.html#bailing-out-of-a-state-update) if the next value is the same as the previous one. Mutating state in place and calling `setState` will not cause a re-render.
329
+
330
+
Normally, you shouldn't mutate local state in React. However, as an escape hatch, you can use an incrementing counter to force a re-render even if the state has not changed:
331
+
332
+
```js
333
+
const [ignored, forceUpdate] =useReducer(x=> x +1, 0);
334
+
335
+
functionhandleClick() {
336
+
forceUpdate();
337
+
}
338
+
```
339
+
340
+
Try to avoid this pattern if possible.
341
+
325
342
### Can I make a ref to a function component?
326
343
327
344
While you shouldn't need this often, you may expose some imperative methods to a parent component with the [`useImperativeHandle`](/docs/hooks-reference.html#useimperativehandle) Hook.
If you update a State Hook to the same value as the current state, React will bail out without rendering the children or firing effects. (React uses the [`Object.is` comparison algorithm](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is#Description).)
95
+
92
96
### `useEffect`
93
97
94
98
```js
@@ -172,20 +176,18 @@ The following Hooks are either variants of the basic ones from the previous sect
An alternative to [`useState`](#usestate). Accepts a reducer of type `(state, action) => newState`, and returns the current state paired with a `dispatch` method. (If you're familiar with Redux, you already know how this works.)
179
183
184
+
`useReducer` is usually preferable to `useState` when you have complex state logic that involves multiple sub-values or when the next state depends on the previous one. `useReducer` also lets you optimize performance for components that trigger deep updates because [you can pass `dispatch` down instead of callbacks](/docs/hooks-faq.html#how-to-avoid-passing-callbacks-down).
185
+
180
186
Here's the counter example from the [`useState`](#usestate) section, rewritten to use a reducer:
181
187
182
188
```js
183
-
constinitialState= {count:0};
184
-
185
189
functionreducer(state, action) {
186
190
switch (action.type) {
187
-
case'reset':
188
-
return initialState;
189
191
case'increment':
190
192
return {count:state.count+1};
191
193
case'decrement':
@@ -202,31 +204,59 @@ function Counter({initialCount}) {
There’s a few different ways to initialize `useReducer` state. You may choose either one depending on the use case. The simplest way to pass the initial state as a second argument:
217
+
218
+
```js{3}
219
+
const [state, dispatch] = useReducer(
220
+
reducer,
221
+
{count: initialCount}
222
+
);
223
+
```
224
+
225
+
>Note
226
+
>
227
+
>React doesn’t use the `state = initialState` argument convention popularized by Redux. The initial value sometimes needs to depend on props and so is specified from the Hook call instead. If you feel strongly about this, you can write `state = initialState` both in the reducer and inside the `useReducer` destructuring assignment, but it's not encouraged.
228
+
215
229
#### Lazy initialization
216
230
217
-
`useReducer` accepts an optional third argument, `initialAction`. If provided, the initial action is applied during the initial render. This is useful for computing an initial state that includes values passed via props:
231
+
If calculating the initial state is expensive, you can initialize it lazily. In that case, you can skip the second argument (and pass `undefined`). The third `useReducer` argument is an optional `init` function that you can provide to calculate the initial value once:
218
232
219
-
```js
220
-
constinitialState= {count:0};
233
+
```js{3-4}
234
+
const [state, dispatch] = useReducer(
235
+
reducer,
236
+
undefined,
237
+
() => ({count: initialCount})
238
+
);
239
+
```
240
+
241
+
#### Lazy initialization with a transform
242
+
243
+
For the most flexibility, you can specify *both* the second `initialArg` and the third `init` function arguments. In that case, the initial state will be set to `init(initialArg)`.
244
+
245
+
This is handy if you want to extract the lazy initialization logic outside your reducer:
246
+
247
+
```js{1-3,11-12,21,26}
248
+
function init(initialCount) {
249
+
return {count: initialCount};
250
+
}
221
251
222
252
function reducer(state, action) {
223
253
switch (action.type) {
224
-
case'reset':
225
-
return {count:action.payload};
226
254
case 'increment':
227
255
return {count: state.count + 1};
228
256
case 'decrement':
229
257
return {count: state.count - 1};
258
+
case 'reset':
259
+
return init(action.payload);
230
260
default:
231
261
// A reducer must always return a valid state.
232
262
// Alternatively you can throw an error if an invalid action is dispatched.
@@ -235,12 +265,7 @@ function reducer(state, action) {
@@ -255,7 +280,9 @@ function Counter({initialCount}) {
255
280
}
256
281
```
257
282
258
-
`useReducer` is usually preferable to `useState` when you have complex state logic that involves multiple sub-values. It also lets you optimize performance for components that trigger deep updates because [you can pass `dispatch` down instead of callbacks](/docs/hooks-faq.html#how-to-avoid-passing-callbacks-down).
283
+
#### Bailing out of a dispatch
284
+
285
+
If you return the same value from a Reducer Hook as the current state, React will bail out without rendering the children or firing effects. (React uses the [`Object.is` comparison algorithm](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is#Description).)
0 commit comments