定义
用法
const [state, dispatch] = useReducer(reducer, initialArg, init);
使用场景
- 当多个 state 需要一起更新时
- 当state 更新逻辑较复杂
- 当下一个 state 依赖于之前的 state,即 编写
setState(prevState => newState)
时
包括但不限于以上三种。
在以上场景中使用时,useReducer()相对于 useState() 的优势
-
上述场景中,使用 useReducer()的好处分析:
- reducer 相对于 useState 可以更好的描述“如何更新状态”。 比如:reducer 能够读取相关的状态、同时更新多个状态。
- 【组件负责发出 action,reducer 负责更新状态】的解耦模式, 使得代码逻辑更加清晰。代码行为更加可以预测(比如:
useEffect
的更新时机更加稳定) - 通过传递 dispatch ,可以减少状态值的传递。
useReducer
总是返回相同的dispatch
函数,这是彻底解耦的标志:状态更新逻辑可以任意变化,而发起action
的渠道始终不变。 - 因前面的解耦模式,
useEffect
函数体、callback function
只需要使用dispatch
来发出action
,而无需直接依赖状态值。因此,在useEffect
、useCallback
、useMemo
的deps
数组中无需包含状态值,也减少了它们更新的需要。不但能提高可读性,而且能提升性能(useCallback
、useMemo
的更新往往会造成子组件的刷新)。
-
示例对比:useState() 和 useReducer()方法
- 使用 useState()方法计数
// 使用 useState()方法 function Counter() { const [count, setCount] = useState(0); const [step, setStep] = useState(1); useEffect(() => { const id = setInterval(() => { setCount(c => c + step); // 依赖其他state来更新 }, 1000); return () => clearInterval(id); // 为了保证setCount中的step是最新的, // 我们还需要在deps数组中指定step }, [step]); return ( <> <h1>{count}</h1> <input value={step} onChange={e => setStep(Number(e.target.value))} /> </> ); }
- 使用 useReducer()方法计数
function Counter() { const initialState = { count: 0, step: 1, }; function reducer(state, action) { console.log(state, action) const { count, step } = state; if (action.type === 'tick') { return { count: count + step, step }; } else if (action.type === 'step') { return { count, step: action.step }; } else { throw new Error(); } } const [state, dispatch] = useReducer(reducer, initialState); const { count, step } = state; useEffect(() => { const id = setInterval(() => { dispatch({ type: 'tick' }); }, 1000); return () => clearInterval(id); }, []); // deps数组不需要包含step return ( <> <h1>count:{count}, step: {step}</h1> <input value={step} onChange={(e) => dispatch({ type: 'step', step: Number(e.target.value) })} /> </> ) }
内联 reducer 的用法讲解
可以将reducer声明在组件内部,从而能够通过闭包访问props、以及前面的hooks结果:
function Counter({ step }) {
const [count, dispatch] = useReducer(reducer, 0);
function reducer(state, action) {
if (action.type === 'tick') {
// 可以通过闭包访问到组件内部的任何变量
// 包括props,以及useReducer之前的hooks的结果
return state + step;
} else {
throw new Error();
}
}
useEffect(() => {
const id = setInterval(() => {
dispatch({ type: 'tick' });
}, 1000);
return () => clearInterval(id);
}, []);
return <h1>{count}</h1>;
}
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!