当您具有涉及多个子值的复杂状态逻辑时,或者当下一个状态取决于上一个状态时,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方法,并且可以在化简器中使用操作逻辑。

10-08 07:09