先简单复习一下redux工作流程
react-hook替换redux方案
要求列表
- useReducer、useContext函数
- action:存放修改state的action,此处与redux的思想一致
- reducer:用来处理不同action,此处我们不提供初始状态的话,默认会去action找。
- rootReducer:当reducer过多的时候,我们可以拆分reducer,拆分reducer后,使用combinReducers合并处理成一个大单一的对象。
- 顶级组件:
- 组件利用provider提供context给子组件
2.useReducer定义,引入reducer并提供初始化状态initialstate
- 组件利用provider提供context给子组件
- 子组件:
- useContext使用顶级组件提供的context
- 如果需要异步请求,使用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/wy1935/p/7109701.html
- 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]);