useReducer、useContext替代redux方案

先简单复习一下redux工作流程

graph LRA[action]-- dispatch.action-->B[store] B--previousState,action -->C[reducers]C-- newState -->BB-- state -->D[组件]

react-hook替换redux方案
要求列表
  • useReducer、useContext函数
  • action:存放修改state的action,此处与redux的思想一致
  • reducer:用来处理不同action,此处我们不提供初始状态的话,默认会去action找。
  • rootReducer:当reducer过多的时候,我们可以拆分reducer,拆分reducer后,使用combinReducers合并处理成一个大单一的对象。
  • 【useReducer、useContext替代redux方案】顶级组件:
    1. 组件利用provider提供context给子组件
      2.useReducer定义,引入reducer并提供初始化状态initialstate
  • 子组件:
    1. useContext使用顶级组件提供的context
    2. 如果需要异步请求,使用useEffect
实现逻辑关键代码:
  • cartReducer.js
    // 定义一个action type const CHANGE_CART_AMOUNT = "CHANGE_CART_AMOUNT"; // 初始化状态数据 const initialState ={ cartList: [] }; // reducer处理action,返回newState export const cartReducer = (state, action) => { switch (action.type) { case CHANGE_CART_AMOUNT: let cartList = state?state.cart.cartList:[]; let cartItem = action.payload; return { cartList: [...cartList, cartItem] }; default: { return state; } } };

    当你除了一个cartReducer之外还有很多reducer,这个时候我们需要拆分并统一管理。
  • rootReducer.js
    import { cartReducer,initialStates } from './cartReducer'; import combineReducers from './combineReducers'; import { layoutInitialState, layoutReducer } from './layoutReducer'; export const initialState = { layout: layoutInitialState, cart: initialStates() }; //拆分reducer后,使用combinReducers合并处理成一个大单一的对象, export const rootReducer = combineReducers({ layout: layoutReducer, cart: cartReducer });

    这里的combineReducer按照redux逻辑,直接写,不是用redux的。
    redux的combineReducer工作原理参考:https://www.cnblogs.com/wy193...
  • combineReducers.js
    //将多个reducer合并成一个reducer const combineReducers = reducers => { return (state = {}, action) => { const newState = {}; for (let key in reducers) { newState[key] = reducers[key](state, action); }return newState; }; }; export default combineReducers;

  • 顶级组件.jsx
    关键代码
    const AppContext = createContext({ state: initialState, dispatch: () => {} }); //由于创建的contenxt AppContext需要在各个组件都用uesContext使用到,所以需要导出。 export default AppContext; //Redux 是通过 createStore(reducer, initialState) 来创建一个 store 实例, // 实例封装了 state 的读写接口和监听接口:getState 、dispatch、subscribe// 在Redux中,store.dispatch 触发事件动作时,Redux 并不会为我们主动重新渲染视图,而是需要我们调用 store.subscribe 在监听函数中手动 render 视图//但 useReducer Hook 是没有使用 store 实例, //而是遵循 Hook 总是返回读写接口的规则,直接通过 [state, dispatch] = useReducer(reducer, initialState) 的方式返回状态的读写接口。const [state, dispatch] = useReducer(rootReducer,initialState); //由于布局数据几乎不变化,我们可以使用缓存,等变化再更新,利用dispatch去触发我们上面定义的rootReducer const contextValue = https://www.it610.com/article/useMemo(() => { return { state, dispatch }; }, [state, dispatch]); //Provider传递参数 return ;

  • 子组件.jsx:在react-hook中,我们只需要触发reducer就能实现像redux-store的dispatch效果一样。
    // 触发dispatch const { state, dispatch } = useAppContext(); const handleCartAmountChange = useCallback((amount, product) => () => { dispatch({ type: "CHANGE_CART_AMOUNT", payload: { ...product, qty: amount } }); }, []); //获取stateconst { state } = useAppContext(); useEffect(() => { setList(state?state.cart.cartList:[]) },[state]);

    推荐阅读