当您具有涉及多个子值的复杂状态逻辑时,或者当下一个状态取决于上一个状态时,useReducer通常比useState更可取。 useReducer还可以让您优化触发深层更新的组件的性能,因为您可以传递调度而不是回调。
(引自https://reactjs.org/docs/hooks-reference.html#usereducer)
我对粗体部分感兴趣,该部分指出在上下文中使用useReducer
而不是useState
。
我尝试了两种变体,但它们似乎没有什么不同。
我比较这两种方法的方式如下:
const [state, updateState] = useState();
const [reducerState, dispatch] = useReducer(myReducerFunction);
我将它们中的每一个传递给一个上下文对象,该上下文对象在一个更深的子对象中使用(我只是运行了单独的测试,将值替换为要测试的函数)。
<ContextObject.Provider value={updateState // dispatch}>
孩子包含这些功能
const updateFunction = useContext(ContextObject);
useEffect(
() => {
console.log('effect triggered');
console.log(updateFunction);
},
[updateFunction]
);
在这两种情况下,当父级重新渲染时(由于另一个局部状态更改),效果永远不会运行,这表明在渲染之间更新功能未更改。
我读引号中的粗体字是否错了?还是我忽略了什么?
最佳答案
useReducer还可让您优化以下组件的性能:
触发深度更新,因为您可以传递调度而不是传递
回调。
上面的语句并不是要表明useState
返回的setter是在每次更新或渲染时新创建的。这意味着当您有复杂的逻辑来更新状态时,您根本不会直接使用setter来更新状态,而是您将编写一个复杂的函数,该函数会依次调用具有更新状态的setter,例如
const handleStateChange = () => {
// lots of logic to derive updated state
updateState(newState);
}
ContextObject.Provider value={{state, handleStateChange}}>
现在,在上述情况下,每次重新渲染父对象时,都会创建一个新的handleStateChange实例,从而使Context Consumer也重新渲染。
解决上述情况的方法是使用
useCallback
并记住状态更新程序方法并使用它。但是,为此,您需要注意与使用方法中的值相关的关闭问题。因此,建议使用
useReducer
,它返回在重新渲染之间不变的dispatch
方法,并且可以在化简器中使用操作逻辑。