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
Copy file name to clipboardexpand all lines: docs/api/hooks.md
+93-45
Original file line number
Diff line number
Diff line change
@@ -11,6 +11,14 @@ React's new ["hooks" APIs](https://reactjs.org/docs/hooks-intro.html) give funct
11
11
12
12
React Redux now offers a set of hook APIs as an alternative to the existing `connect()` Higher Order Component. These APIs allow you to subscribe to the Redux store and dispatch actions, without having to wrap your components in `connect()`.
13
13
14
+
:::tip
15
+
16
+
**We recommend using the React-Redux hooks API as the default approach in your React components.**
17
+
18
+
The existing `connect` API still works and will continue to be supported, but the hooks API is simpler and works better with TypeScript.
Allows you to extract data from the Redux store state, using a selector function.
40
48
41
-
> **Note**: The selector function should be [pure](https://en.wikipedia.org/wiki/Pure_function) since it is potentially executed multiple times and at arbitrary points in time.
49
+
:::info
50
+
51
+
The selector function should be [pure](https://en.wikipedia.org/wiki/Pure_function) since it is potentially executed multiple times and at arbitrary points in time.
52
+
53
+
:::
42
54
43
55
The selector is approximately equivalent to the [`mapStateToProps` argument to `connect`](../using-react-redux/connect-mapstate) conceptually. The selector will be called with the entire Redux store state as its only argument. The selector will be run whenever the function component renders (unless its reference hasn't changed since a previous render of the component so that a cached result can be returned by the hook without re-running the selector). `useSelector()` will also subscribe to the Redux store, and run your selector whenever an action is dispatched.
44
56
@@ -50,7 +62,11 @@ However, there are some differences between the selectors passed to `useSelector
50
62
- Extra care must be taken when using memoizing selectors (see examples below for more details).
51
63
-`useSelector()` uses strict `===` reference equality checks by default, not shallow equality (see the following section for more details).
52
64
53
-
> **Note**: There are potential edge cases with using props in selectors that may cause errors. See the [Usage Warnings](#usage-warnings) section of this page for further details.
65
+
:::info
66
+
67
+
There are potential edge cases with using props in selectors that may cause issues. See the [Usage Warnings](#usage-warnings) section of this page for further details.
68
+
69
+
:::
54
70
55
71
You may call `useSelector()` multiple times within a single function component. Each call to `useSelector()` creates an individual subscription to the Redux store. Because of the React update batching behavior used in React Redux v7, a dispatched action that causes multiple `useSelector()`s in the same component to return new values _should_ only result in a single re-render.
56
72
@@ -91,7 +107,7 @@ import React from 'react'
91
107
import { useSelector } from'react-redux'
92
108
93
109
exportconstCounterComponent= () => {
94
-
constcounter=useSelector((state)=>state.counter)
110
+
constcounter=useSelector(state=>state.counter)
95
111
return<div>{counter}</div>
96
112
}
97
113
```
@@ -102,8 +118,8 @@ Using props via closure to determine what to extract:
This hook returns a reference to the `dispatch` function from the Redux store. You may use it to dispatch actions as needed.
221
234
222
-
_Note: like in [React's `useReducer`](https://reactjs.org/docs/hooks-reference.html#usereducer), the returned `dispatch` function identity is stable and won't change on re-renders (unless you change the `store` being passed to the `<Provider>`, which would be extremely unusual)._
Reminder: when passing a callback using `dispatch` to a child component, you should memoize it with [`useCallback`](https://reactjs.org/docs/hooks-reference.html#usecallback), just like you should memoize any passed callback. This avoids unnecessary rendering of child components due to the changed callback reference. You can safely pass `[dispatch]` in the dependency array for the `useCallback` call - since `dispatch` won't change, the callback will be reused properly (as it should). For example:
255
+
When passing a callback using `dispatch` to a child component, you may sometimes want to memoize it with [`useCallback`](https://reactjs.org/docs/hooks-reference.html#usecallback). _If_ the child component is trying to optimize render behavior using `React.memo()` or similar, this avoids unnecessary rendering of child components due to the changed callback reference.
The `dispatch` function reference will be stable as long as the same store instance is being passed to the `<Provider>`.
284
+
Normally, that store instance never changes in an application.
285
+
286
+
However, the React hooks lint rules do not know that `dispatch` should be stable, and will warn that the `dispatch` variable
287
+
should be added to dependency arrays for `useEffect` and `useCallback`. The simplest solution is to do just that:
288
+
289
+
````js
290
+
exportconstTodos() = () => {
291
+
constdispatch=useDispatch();
292
+
293
+
useEffect(() => {
294
+
dispatch(fetchTodos())
295
+
// highlight-start
296
+
// Safe to add dispatch to the dependencies array
297
+
}, [dispatch])
298
+
// highlight-end
299
+
}
300
+
301
+
:::
302
+
270
303
## `useStore()`
271
304
272
305
```js
@@ -304,7 +337,7 @@ import {
304
337
Provider,
305
338
createStoreHook,
306
339
createDispatchHook,
307
-
createSelectorHook,
340
+
createSelectorHook
308
341
} from 'react-redux'
309
342
310
343
const MyContext = React.createContext(null)
@@ -329,6 +362,12 @@ export function MyProvider({ children }) {
329
362
330
363
### Stale Props and "Zombie Children"
331
364
365
+
:::info
366
+
367
+
The React-Redux hooks API has been production-ready since we released it in v7.1.0, and **we recommend using the hooks API as the default approach in your components**. However, there are a couple of edge cases that can occur, and **we're documenting those so that you can be aware of them**.
368
+
369
+
:::
370
+
332
371
One of the most difficult aspects of React Redux's implementation is ensuring that if your `mapStateToProps` function is defined as `(state, ownProps)`, it will be called with the "latest" props every time. Up through version 4, there were recurring bugs reported involving edge case situations, such as errors thrown from a `mapState` function for a list item whose data had just been deleted.
333
372
334
373
Starting with version 5, React Redux has attempted to guarantee that consistency with `ownProps`. In version 7, that is implemented using a custom `Subscription` class internally in `connect()`, which forms a nested hierarchy. This ensures that connected components lower in the tree will only receive store update notifications once the nearest connected ancestor has been updated. However, this relies on each `connect()` instance overriding part of the internal React context, supplying its own unique `Subscription` instance to form that nesting, and rendering the `<ReactReduxContext.Provider>` with that new context value.
@@ -358,7 +397,15 @@ If you prefer to deal with this issue yourself, here are some possible options f
358
397
- In cases where you do rely on props in your selector function _and_ those props may change over time, _or_ the data you're extracting may be based on items that can be deleted, try writing the selector functions defensively. Don't just reach straight into `state.todos[props.id].name` - read `state.todos[props.id]` first, and verify that it exists before trying to read `todo.name`.
359
398
- Because `connect` adds the necessary `Subscription` to the context provider and delays evaluating child subscriptions until the connected component has re-rendered, putting a connected component in the component tree just above the component using `useSelector` will prevent these issues as long as the connected component gets re-rendered due to the same store update as the hooks component.
360
399
361
-
> **Note**: For a longer description of this issue, see ["Stale props and zombie children in Redux" by Kai Hao](https://kaihao.dev/posts/Stale-props-and-zombie-children-in-Redux), [this chat log that describes the problems in more detail](https://gist.github.com/markerikson/faac6ae4aca7b82a058e13216a7888ec), and [issue #1179](https://github.com/reduxjs/react-redux/issues/1179).
400
+
:::info
401
+
402
+
For a longer description of these scenarios, see:
403
+
404
+
- ["Stale props and zombie children in Redux" by Kai Hao](https://kaihao.dev/posts/Stale-props-and-zombie-children-in-Redux)
405
+
- [this chat log that describes the problems in more detail](https://gist.github.com/markerikson/faac6ae4aca7b82a058e13216a7888ec)
@@ -431,3 +478,4 @@ export function useShallowEqualSelector(selector) {
431
478
### Additional considerations when using hooks
432
479
433
480
There are some architectural trade offs to take into consideration when deciding whether to use hooks or not. Mark Erikson summarizes these nicely in his two blog posts [Thoughts on React Hooks, Redux, and Separation of Concerns](https://blog.isquaredsoftware.com/2019/07/blogged-answers-thoughts-on-hooks/) and [Hooks, HOCs, and Tradeoffs](https://blog.isquaredsoftware.com/2019/09/presentation-hooks-hocs-tradeoffs/).
<strong>Designed to work with React's component model</strong>.
25
-
{' '} You define how to extract the values your component needs from Redux, and your component receives them as props.
28
+
<strong>Designed to work with React's component model</strong>. You
29
+
define how to extract the values your component needs from Redux, and
30
+
your component receives them as props.
26
31
</p>
27
32
),
28
33
image: <imgsrc="img/noun_Check_1870817.svg"/>,
@@ -32,7 +37,9 @@ const features = [
32
37
{
33
38
content: (
34
39
<p>
35
-
Creates wrapper components that <strong>manage the store interaction logic for you</strong>, so you don't have to write it yourself.
40
+
Creates wrapper components that{' '}
41
+
<strong>manage the store interaction logic for you</strong>, so you
42
+
don't have to write it yourself.
36
43
</p>
37
44
),
38
45
image: <imgsrc="img/noun_Box_1664404.svg"/>,
@@ -42,13 +49,15 @@ const features = [
42
49
{
43
50
content: (
44
51
<p>
45
-
Automatically implements <strong>complex performance optimizations</strong>, so that your own component only re-renders when the data it needs has actually changed.
52
+
Automatically implements{' '}
53
+
<strong>complex performance optimizations</strong>, so that your own
54
+
component only re-renders when the data it needs has actually changed.
Copy file name to clipboardexpand all lines: website/versioned_docs/version-7.1/api/hooks.md
+99-42
Original file line number
Diff line number
Diff line change
@@ -11,6 +11,14 @@ React's new ["hooks" APIs](https://reactjs.org/docs/hooks-intro.html) give funct
11
11
12
12
React Redux now offers a set of hook APIs as an alternative to the existing `connect()` Higher Order Component. These APIs allow you to subscribe to the Redux store and dispatch actions, without having to wrap your components in `connect()`.
13
13
14
+
:::tip
15
+
16
+
**We recommend using the React-Redux hooks API as the default approach in your React components.**
17
+
18
+
The existing `connect` API still works and will continue to be supported, but the hooks API is simpler and works better with TypeScript.
19
+
20
+
:::
21
+
14
22
These hooks were first added in v7.1.0.
15
23
16
24
## Using Hooks in a React Redux App
@@ -33,24 +41,32 @@ From there, you may import any of the listed React Redux hooks APIs and use them
Allows you to extract data from the Redux store state, using a selector function.
40
48
41
-
> **Note**: The selector function should be [pure](https://en.wikipedia.org/wiki/Pure_function) since it is potentially executed multiple times and at arbitrary points in time.
49
+
:::info
50
+
51
+
The selector function should be [pure](https://en.wikipedia.org/wiki/Pure_function) since it is potentially executed multiple times and at arbitrary points in time.
52
+
53
+
:::
42
54
43
55
The selector is approximately equivalent to the [`mapStateToProps` argument to `connect`](../using-react-redux/connect-mapstate) conceptually. The selector will be called with the entire Redux store state as its only argument. The selector will be run whenever the function component renders (unless its reference hasn't changed since a previous render of the component so that a cached result can be returned by the hook without re-running the selector). `useSelector()` will also subscribe to the Redux store, and run your selector whenever an action is dispatched.
44
56
45
57
However, there are some differences between the selectors passed to `useSelector()` and a `mapState` function:
46
58
47
59
- The selector may return any value as a result, not just an object. The return value of the selector will be used as the return value of the `useSelector()` hook.
48
-
- When an action is dispatched, `useSelector()` will do a shallow comparison of the previous selector result value and the current result value. If they are different, the component will be forced to re-render. If they are the same, the component will not re-render.
60
+
- When an action is dispatched, `useSelector()` will do a reference comparison of the previous selector result value and the current result value. If they are different, the component will be forced to re-render. If they are the same, the component will not re-render.
49
61
- The selector function does _not_ receive an `ownProps` argument. However, props can be used through closure (see the examples below) or by using a curried selector.
50
62
- Extra care must be taken when using memoizing selectors (see examples below for more details).
51
63
-`useSelector()` uses strict `===` reference equality checks by default, not shallow equality (see the following section for more details).
52
64
53
-
> **Note**: There are potential edge cases with using props in selectors that may cause errors. See the [Usage Warnings](#usage-warnings) section of this page for further details.
65
+
:::info
66
+
67
+
There are potential edge cases with using props in selectors that may cause issues. See the [Usage Warnings](#usage-warnings) section of this page for further details.
68
+
69
+
:::
54
70
55
71
You may call `useSelector()` multiple times within a single function component. Each call to `useSelector()` creates an individual subscription to the Redux store. Because of the React update batching behavior used in React Redux v7, a dispatched action that causes multiple `useSelector()`s in the same component to return new values _should_ only result in a single re-render.
This hook returns a reference to the `dispatch` function from the Redux store. You may use it to dispatch actions as needed.
219
235
220
-
*Note: like in [React's `useReducer`](https://reactjs.org/docs/hooks-reference.html#usereducer), the returned `dispatch` function identity is stable and won't change on re-renders (unless you change the `store` being passed to the `<Provider>`, which would be extremely unusual).*
Reminder: when passing a callback using `dispatch` to a child component, you should memoize it with [`useCallback`](https://reactjs.org/docs/hooks-reference.html#usecallback), just like you should memoize any passed callback. This avoids unnecessary rendering of child components due to the changed callback reference. You can safely pass `[dispatch]` in the dependency array for the `useCallback` call - since `dispatch` won't change, the callback will be reused properly (as it should). For example:
257
+
When passing a callback using `dispatch` to a child component, you may sometimes want to memoize it with [`useCallback`](https://reactjs.org/docs/hooks-reference.html#usecallback). _If_ the child component is trying to optimize render behavior using `React.memo()` or similar, this avoids unnecessary rendering of child components due to the changed callback reference.
The React-Redux hooks API has been production-ready since we released it in v7.1.0, and **we recommend using the hooks API as the default approach in your components**. However, there are a couple of edge cases that can occur, and **we're documenting those so that you can be aware of them**.
336
+
337
+
:::
338
+
297
339
One of the most difficult aspects of React Redux's implementation is ensuring that if your `mapStateToProps`function is defined as `(state, ownProps)`, it will be called with the "latest" props every time. Up through version 4, there were recurring bugs reported involving edge case situations, such as errors thrown from a `mapState` function for a list item whose data had just been deleted.
298
340
299
341
Starting with version 5, React Redux has attempted to guarantee that consistency with `ownProps`. In version 7, that is implemented using a custom `Subscription` class internally in `connect()`, which forms a nested hierarchy. This ensures that connected components lower in the tree will only receive store update notifications once the nearest connected ancestor has been updated. However, this relies on each `connect()` instance overriding part of the internal React context, supplying its own unique `Subscription` instance to form that nesting, and rendering the `<ReactReduxContext.Provider>` with that new context value.
@@ -323,7 +365,15 @@ If you prefer to deal with this issue yourself, here are some possible options f
323
365
- In cases where you do rely on props in your selector function _and_ those props may change over time, _or_ the data you're extracting may be based on items that can be deleted, try writing the selector functions defensively. Don't just reach straight into `state.todos[props.id].name` - read `state.todos[props.id]` first, and verify that it exists before trying to read `todo.name`.
324
366
- Because `connect` adds the necessary `Subscription` to the context provider and delays evaluating child subscriptions until the connected component has re-rendered, putting a connected component in the component tree just above the component using `useSelector` will prevent these issues as long as the connected component gets re-rendered due to the same store update as the hooks component.
325
367
326
-
> **Note**: For a longer description of this issue, see ["Stale props and zombie children in Redux" by Kai Hao](https://kaihao.dev/posts/Stale-props-and-zombie-children-in-Redux), [this chat log that describes the problems in more detail](https://gist.github.com/markerikson/faac6ae4aca7b82a058e13216a7888ec), and [issue #1179](https://github.com/reduxjs/react-redux/issues/1179).
368
+
:::info
369
+
370
+
For a longer description of these scenarios, see:
371
+
372
+
- ["Stale props and zombie children in Redux" by Kai Hao](https://kaihao.dev/posts/Stale-props-and-zombie-children-in-Redux)
373
+
- [this chat log that describes the problems in more detail](https://gist.github.com/markerikson/faac6ae4aca7b82a058e13216a7888ec)
There are some architectural trade offs to take into consideration when deciding whether to use hooks or not. Mark Erikson summarizes these nicely in his two blog posts [Thoughts on React Hooks, Redux, and Separation of Concerns](https://blog.isquaredsoftware.com/2019/07/blogged-answers-thoughts-on-hooks/) and [Hooks, HOCs, and Tradeoffs](https://blog.isquaredsoftware.com/2019/09/presentation-hooks-hocs-tradeoffs/).
Copy file name to clipboardexpand all lines: website/versioned_docs/version-7.2/api/hooks.md
+82-34
Original file line number
Diff line number
Diff line change
@@ -11,6 +11,14 @@ React's new ["hooks" APIs](https://reactjs.org/docs/hooks-intro.html) give funct
11
11
12
12
React Redux now offers a set of hook APIs as an alternative to the existing `connect()` Higher Order Component. These APIs allow you to subscribe to the Redux store and dispatch actions, without having to wrap your components in `connect()`.
13
13
14
+
:::tip
15
+
16
+
**We recommend using the React-Redux hooks API as the default approach in your React components.**
17
+
18
+
The existing `connect` API still works and will continue to be supported, but the hooks API is simpler and works better with TypeScript.
Allows you to extract data from the Redux store state, using a selector function.
40
48
41
-
> **Note**: The selector function should be [pure](https://en.wikipedia.org/wiki/Pure_function) since it is potentially executed multiple times and at arbitrary points in time.
49
+
:::info
50
+
51
+
The selector function should be [pure](https://en.wikipedia.org/wiki/Pure_function) since it is potentially executed multiple times and at arbitrary points in time.
52
+
53
+
:::
42
54
43
55
The selector is approximately equivalent to the [`mapStateToProps` argument to `connect`](../using-react-redux/connect-mapstate) conceptually. The selector will be called with the entire Redux store state as its only argument. The selector will be run whenever the function component renders (unless its reference hasn't changed since a previous render of the component so that a cached result can be returned by the hook without re-running the selector). `useSelector()` will also subscribe to the Redux store, and run your selector whenever an action is dispatched.
44
56
@@ -50,7 +62,11 @@ However, there are some differences between the selectors passed to `useSelector
50
62
- Extra care must be taken when using memoizing selectors (see examples below for more details).
51
63
-`useSelector()` uses strict `===` reference equality checks by default, not shallow equality (see the following section for more details).
52
64
53
-
> **Note**: There are potential edge cases with using props in selectors that may cause errors. See the [Usage Warnings](#usage-warnings) section of this page for further details.
65
+
:::info
66
+
67
+
There are potential edge cases with using props in selectors that may cause issues. See the [Usage Warnings](#usage-warnings) section of this page for further details.
68
+
69
+
:::
54
70
55
71
You may call `useSelector()` multiple times within a single function component. Each call to `useSelector()` creates an individual subscription to the Redux store. Because of the React update batching behavior used in React Redux v7, a dispatched action that causes multiple `useSelector()`s in the same component to return new values _should_ only result in a single re-render.
This hook returns a reference to the `dispatch` function from the Redux store. You may use it to dispatch actions as needed.
221
235
222
-
*Note: like in [React's `useReducer`](https://reactjs.org/docs/hooks-reference.html#usereducer), the returned `dispatch` function identity is stable and won't change on re-renders (unless you change the `store` being passed to the `<Provider>`, which would be extremely unusual).*
Reminder: when passing a callback using `dispatch` to a child component, you should memoize it with [`useCallback`](https://reactjs.org/docs/hooks-reference.html#usecallback), just like you should memoize any passed callback. This avoids unnecessary rendering of child components due to the changed callback reference. You can safely pass `[dispatch]` in the dependency array for the `useCallback` call - since `dispatch` won't change, the callback will be reused properly (as it should). For example:
257
+
When passing a callback using `dispatch` to a child component, you may sometimes want to memoize it with [`useCallback`](https://reactjs.org/docs/hooks-reference.html#usecallback). _If_ the child component is trying to optimize render behavior using `React.memo()` or similar, this avoids unnecessary rendering of child components due to the changed callback reference.
The `dispatch` function reference will be stable as long as the same store instance is being passed to the `<Provider>`.
286
+
Normally, that store instance never changes in an application.
287
+
288
+
However, the React hooks lint rules do not know that `dispatch` should be stable, and will warn that the `dispatch` variable
289
+
should be added to dependency arrays for `useEffect` and `useCallback`. The simplest solution is to do just that:
290
+
291
+
````js
292
+
exportconstTodos() = () => {
293
+
constdispatch=useDispatch();
294
+
295
+
useEffect(() => {
296
+
dispatch(fetchTodos())
297
+
// highlight-start
298
+
// Safe to add dispatch to the dependencies array
299
+
}, [dispatch])
300
+
// highlight-end
301
+
}
302
+
303
+
:::
270
304
## `useStore()`
271
305
272
306
```js
@@ -329,6 +363,12 @@ export function MyProvider({ children }) {
329
363
330
364
### Stale Props and "Zombie Children"
331
365
366
+
:::info
367
+
368
+
The React-Redux hooks API has been production-ready since we released it in v7.1.0, and **we recommend using the hooks API as the default approach in your components**. However, there are a couple of edge cases that can occur, and **we're documenting those so that you can be aware of them**.
369
+
370
+
:::
371
+
332
372
One of the most difficult aspects of React Redux's implementation is ensuring that if your `mapStateToProps` function is defined as `(state, ownProps)`, it will be called with the "latest" props every time. Up through version 4, there were recurring bugs reported involving edge case situations, such as errors thrown from a `mapState` function for a list item whose data had just been deleted.
333
373
334
374
Starting with version 5, React Redux has attempted to guarantee that consistency with `ownProps`. In version 7, that is implemented using a custom `Subscription` class internally in `connect()`, which forms a nested hierarchy. This ensures that connected components lower in the tree will only receive store update notifications once the nearest connected ancestor has been updated. However, this relies on each `connect()` instance overriding part of the internal React context, supplying its own unique `Subscription` instance to form that nesting, and rendering the `<ReactReduxContext.Provider>` with that new context value.
@@ -358,7 +398,15 @@ If you prefer to deal with this issue yourself, here are some possible options f
358
398
- In cases where you do rely on props in your selector function _and_ those props may change over time, _or_ the data you're extracting may be based on items that can be deleted, try writing the selector functions defensively. Don't just reach straight into `state.todos[props.id].name` - read `state.todos[props.id]` first, and verify that it exists before trying to read `todo.name`.
359
399
- Because `connect` adds the necessary `Subscription` to the context provider and delays evaluating child subscriptions until the connected component has re-rendered, putting a connected component in the component tree just above the component using `useSelector` will prevent these issues as long as the connected component gets re-rendered due to the same store update as the hooks component.
360
400
361
-
> **Note**: For a longer description of this issue, see ["Stale props and zombie children in Redux" by Kai Hao](https://kaihao.dev/posts/Stale-props-and-zombie-children-in-Redux), [this chat log that describes the problems in more detail](https://gist.github.com/markerikson/faac6ae4aca7b82a058e13216a7888ec), and [issue #1179](https://github.com/reduxjs/react-redux/issues/1179).
401
+
:::info
402
+
403
+
For a longer description of these scenarios, see:
404
+
405
+
- ["Stale props and zombie children in Redux" by Kai Hao](https://kaihao.dev/posts/Stale-props-and-zombie-children-in-Redux)
406
+
- [this chat log that describes the problems in more detail](https://gist.github.com/markerikson/faac6ae4aca7b82a058e13216a7888ec)
0 commit comments