React Hooks系列之useReducer
useReducer介绍
useState 的替代方案,它更适合一些逻辑较复杂且包含多个子值,或者下一个 state 依赖于之前的 state 等的特定场景
类似 Redux 中的功能 reducer。
它接收一个形如 (state, action) => newState
的reducer,并返回当前的 state 以及与其配套的 dispatch 方法。
const [state, dispatch] = useReducer(reducer, initState, initAction)
参数介绍
- reducer 是一个函数,就是一个函数类似
(state, action) => newState
的函数,传入 上一个 state 和 本次的 action, 根据 action 状态处理并更新 state - initState 是初始化的 state,也就是默认值
- initAction 是useReducer 初次执行时被处理的 action,其实惰性初始化,这么做可以将用于计算 state 的逻辑提取到 reducer 外部,这也为将来对重置 state 的action 做处理提供了便利
返回值state,dispatch介绍
- state 状态值
- dispatch 是更新 state 的方法,他接受 action 作为参数。useReducer 只需要调用dispatch(action) 方法传入 action 即可更新 state
useContext 可以解决组件间的数据共享问题,而useReducer 可以解决复杂状态管理的问题,如果把他们结合起来使用,就可以实现 redux 的功能了
useRuducer使用
基本使用
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
function App() {
const [state, dispatch] = useReducer(reducer, {
count: 0
});
return (
<>
点击次数: {state.count}
<button onClick={() => dispatch({type: 'increment'})}>+</button>
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
</>
);
}
惰性初始化
你可以选择惰性地创建初始 state。为此,需要将 init 函数作为 useReducer 的第三个参数传入,这样初始 state 将被 设置为 init(initialArg)。
这么做可以将用于计算 state 的逻辑提取到 reducer 外部,这也为将来对重置 state 的 action 做处理提供了便利:
function init(initialCount) {
return {count: initialCount};
}
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
case 'reset':
return init(action.payload);
default:
throw new Error();
}
}
function Counter({initialCount}) {
const [state, dispatch] = useReducer(reducer, initialCount, init);
return (
<>
Count: {state.count}
<button
onClick={() => dispatch({type: 'reset', payload: initialCount})}>
Reset
</button>
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
</>
);
}
注意: React 会确保 dispatch 函数的标识是稳定的,并且不会在组件重新渲染时改变,这就是为什么可以安全地从 useRffect 或 useCallback 的依赖列表中省略 dispatch