hooks 首次添加于版本 v7.1.0

React Redux 现在提供了一组 Hook,用以代替 connect() 高阶组件,这些 API 允许订阅 Redux statedispatch actions ,而不必将组建包装在 connect()

使用前提:和使用 connect() 一样,你首先应该将整个应用包裹在 <Provider> 中,使得 store 暴露在整个组件树中

  1. const store = createStore(rootReducer)
  2. ReactDOM.render(
  3. <Provider store={store}>
  4. <App />
  5. </Provider>,
  6. document.getElementById('root')
  7. )

1. useSelector

使用选择器功能从 Redux store状态中提取数据,类似于 connect 中的 mapStateToProps 参数。将以整个 Redux store状态作为唯一参数来调用选择器

  1. const result: any = useSelector(selector: Function, equalityFn?: Function)

⚠️:选择器函数应是一个纯函数

  • useSelector()同样会订阅 Redux 的 store,并且在你每分发 dispatch 一个 action 时,都会被执行一次
  • selector:接收 store 的 state 整个值,它的返回值将作为 useSeletor() 的返回值
  • 当 dispatch 了一个 action 时,useSelector会将上一次调用 selector 函数的执行结果与当前调用的结果进行引用(===)比较,如果不一样,组件会被强制重新渲染。如果一样,就不会被重新渲染。

    用法举例

    ```jsx import React from ‘react’ import { useSelector } from ‘react-redux’

export const CounterComponent = () => { const counter = useSelector(state => state.counter) return

{counter}
}

  1. 在使用 `useSelector` 时使用单行箭头函数,会导致在每次渲染期间都会创建一个新的 selector 函数。可以看出,这样的 selector 函数并没有维持任何的内部状态。
  2. 解决方式:使用 reselect 库,实现记忆化的 selector 函数
  3. ```jsx
  4. import React from 'react'
  5. import { useSelector } from 'react-redux'
  6. import { createSelector } from 'reselect'
  7. // 返回 isDone 的 todo 的长度
  8. const selectNumOfDoneTodos = createSelector(
  9. state => state.todos,
  10. todos => todos.filter(todo => todo.isDone).length
  11. )
  12. export const DoneTodosCounter = () => {
  13. const NumOfDoneTodos = useSelector(selectNumOfDoneTodos)
  14. return <div>{NumOfDoneTodos}</div>
  15. }
  16. export const App = () => {
  17. return (
  18. <>
  19. <span>Number of done todos:</span>
  20. <DoneTodosCounter />
  21. </>
  22. )
  23. }

2. useDispatch

这个 hook 返回 Redux store 的 分发(dispatch) 函数的引用,用来 dispatch 某些需要的 action

  1. const dispatch = useDispatch()

用法举例

  1. import React from 'react'
  2. import { useDispatch } from 'react-redux'
  3. export const CounterComponent = ({ value }) => {
  4. const dispatch = useDispatch()
  5. return (
  6. <div>
  7. <span>{value}</span>
  8. <button onClick={() => dispatch({ type: 'increment-counter' })}>
  9. Increment counter
  10. </button>
  11. </div>
  12. )
  13. }

3. useStore

这个 hook 返回传递给 组件的 Redux store 的引用

这个 hook 也许不应该被经常使用。 你应该将 useSelector() 作为你的首选。 但是,在一些不常见的场景下,你需要访问 store,这个还是有用的,比如替换 store 的 reducers

用法举例

  1. import React from 'react'
  2. import { useStore } from 'react-redux'
  3. export const CounterComponent = ({ value }) => {
  4. const store = useStore()
  5. // EXAMPLE ONLY! Do not do this in a real app.
  6. // The component will not automatically update if the store state changes
  7. return <div>{store.getState()}</div>
  8. }

参考资料

[译] React-Redux 官方 Hooks 文档说明