redux hooks
useReducer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| import React, { useReducer } from "react";
const initialState = { num: 0 };
const reducer = (state, action) => { switch (action.type) { case "decrement": return { ...state, num: state.num - 1 }; case "increment": return { ...state, num: state.num + 1 }; default: return state; } };
const ComponentUseReducer = () => { const [state, dispatch] = useReducer(reducer, initialState);
const { num } = state; return ( <div> <h2>Using useReducer</h2> Number: {num} <button onClick={() => dispatch({ type: "increment" })}>+</button> <button onClick={() => dispatch({ type: "decrement" })}>-</button> </div> ); };
export default ComponentUseReducer;
|
可以看到 useReducer 的逻辑脱离了 UI,可以独立复用。reducer 就是一个单纯的 Js 方法,我们可以对 reducer 进行单独测试,甚至可以在 chrome 中进行调试

实际使用中 reducer 应该以单独的文件存在,上面例子为了简单起见放到了一起。
useReducer虽然很好地分离了逻辑和 UI,但是无法像 redux 一样进行跨组件的状态共享,例如子组件无法方便的访问到num.
但 ueReducer 是可以性能优化。 dispatch 自带memorize(缓存),所以子组件不会进行重复的 re-render
useSelector、useDispatch
如上所述,Hooks 仍然无法替代 Redux 的作用,特别是在状态共享方面。庆幸的是 react-redux 7.1 之后也可以使用 useSelector、useDispatch 等 HooksApi 替代 connect,减少模板代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| import React from "react"; import { createStore } from "redux"; import { Provider, useSelector, useDispatch } from "react-redux";
const initialState = { num: 0 };
const reducer = (state, action) => { switch (action.type) { case "decrement": return { ...state, num: state.num - 1 }; case "increment": return { ...state, num: state.num + 1 }; default: return state; } };
const store = createStore(reducer, initialState);
const ComponentUseReactRedux = () => { return ( <div> <h2>ComponentUseReactRedux</h2> <Provider store={store}> <ChildComponentUseReactRedux /> </Provider> </div> ); };
const ChildComponentUseReactRedux = () => { const num = useSelector((state) => state.num); const dispatch = useDispatch(); return ( <div> <h3>Using useSelector, useDispatch</h3> Number: {num} <button onClick={() => dispatch({ type: "increment" })}>+</button> <button onClick={() => dispatch({ type: "decrement" })}>-</button> </div> ); };
export default ComponentUseReactRedux;
|
createStore
| const store = createStore(reducer, initialState);
<Provider store={store}> <ChildComponentUseReactRedux /> </Provider>;
|
useSelector
| const num = useSelector((state) => state.num);
const selector = (state) => { return state.num; }; const num = useSelector(selector);
|
useDispatch
| const dispatch = useDispatch();
const ComponentUseReactRedux = () => { return ( <div> <h2>ComponentUseReactRedux</h2> <Provider store={store}> <ChildComponentUseReactRedux /> <ChildComponentUseReactRedux /> </Provider> </div> ); };
|

最后
通过 useSelector、useDispatch 等方法,我们可以用 Hooks 方法完成 Redux 的功能,Hooks 和 Redux 之间没有替代关系,应该更好地共存和融合。