乐趣区

关于react.js:useReduceruseContext替代redux方案

先简略温习一下 redux 工作流程

graph LR

A[action]-- dispatch.action-->B[store]
B--previousState,action -->C[reducers]

C-- newState -->B

B-- state -->D[组件]

react-hook 替换 redux 计划

要求列表

  • useReducer、useContext 函数
  • action:寄存批改 state 的 action,此处与 redux 的思维统一
  • reducer:用来解决不同 action, 此处咱们不提供初始状态的话,默认会去 action 找。
  • rootReducer:当 reducer 过多的时候,咱们能够拆分 reducer,拆分 reducer 后,应用 combinReducers 合并解决成一个大繁多的对象。
  • 顶级组件:

    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 = useMemo(() => {
      return {
        state,
        dispatch
      };
    }, [state, dispatch]);
    
    //Provider 传递参数
    return <AppContext.Provider value={contextValue}>
      </AppContext.Provider>;
      
    
  • 子组件.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
        }
      });
    }, []);
    
    // 获取 state
    
    const {state} = useAppContext();
    
    useEffect(() => {setList(state?state.cart.cartList:[])
    },[state]);  
退出移动版