useState与useReducer

JDa*_*oer 11 reactjs react-hooks

当您具有涉及多个子值的复杂状态逻辑时,或者当下一个状态取决于上一个状态时,useReducer通常比useState更可取。useReducer还可以让您优化触发深层更新的组件的性能,因为您可以传递调度而不是回调。

(引自https://reactjs.org/docs/hooks-reference.html#usereducer

我对粗体部分感兴趣,该部分指出useReduceruseState在上下文中使用而不是使用。

我尝试了两种变体,但它们似乎没有什么不同。

我比较这两种方法的方式如下:

const [state, updateState] = useState();
const [reducerState, dispatch] = useReducer(myReducerFunction);
Run Code Online (Sandbox Code Playgroud)

我将它们每个都传递给一个上下文对象,该上下文对象被一个更深的孩子使用(我只是运行了单独的测试,将值替换为要测试的函数)。

<ContextObject.Provider value={updateState // dispatch}>

孩子包含这些功能

const updateFunction = useContext(ContextObject);
useEffect(
  () => {
    console.log('effect triggered');
    console.log(updateFunction);
  },
  [updateFunction]
);

Run Code Online (Sandbox Code Playgroud)

在这两种情况下,当父级重新渲染时(由于另一个局部状态更改),效果永远不会运行,这表明在渲染之间更新功能未更改。我看错了引号中的粗体字吗?还是我忽略了什么?

Shu*_*tri 7

useReducer还可以让您优化触发深层更新的组件的性能,因为您可以传递调度而不是回调。

上面的语句并不是要表明useState在每次更新或渲染时都正在重新创建由返回的setter 。这意味着当您有复杂的逻辑来更新状态时,您根本不会直接使用setter来更新状态,而是您将编写一个复杂的函数,该函数会依次调用具有更新状态的setter,例如

const handleStateChange = () => {
   // lots of logic to derive updated state
   updateState(newState);
}

ContextObject.Provider value={{state, handleStateChange}}>
Run Code Online (Sandbox Code Playgroud)

现在,在上述情况下,每次重新渲染父对象时,都会创建一个新的handleStateChange实例,从而使Context Consumer也重新渲染。

上述情况的解决方案是使用useCallback并记住状态更新程序方法并使用它。但是,为此,您需要注意与使用方法中的值相关的关闭问题。

因此,建议使用useReducerwhich返回dispatch在重新渲染之间不变的方法,并且可以在化简器中使用操作逻辑。

  • 另外,旁注:在您的示例中,它始终会使子对象重新渲染,因为每次渲染都会创建值对象,并且对象是通过引用的,因此不一样:) (2认同)
  • 确实,我只是想演示一下。 (2认同)
  • @ecoe,没有 useReducer 在功能上不等同于 useCallback。useCallback 用于记忆函数,而 useReducer 用于存储和更新状态。useReducer 返回的调度在每次渲染时都不会改变,因此可以将其传递给应用记忆化的子组件 (2认同)

Kai*_*ash 5

useReducer 和 useState 的实际观察 -

使用状态:

在我的 React Native 项目中,我有 1 个屏幕,其中包含使用useState.

useEffect (componentDidMount)根据某些条件调用 api 并获取响应,我设置这 25 个状态,为每个函数调用 25 个状态设置器函数。

我已经设置了重新渲染计数器并检查了我的屏幕是否重新渲染了14次数。

重新渲染计数同样:

let count = 0;

export default function Home(props) {
  count++;
  console.log({count});
  //...
  // Rest of the code
 }
Run Code Online (Sandbox Code Playgroud)

使用Reducer:

然后我将这 25 个状态移到 useReducer 状态中,并且仅使用单个操作来更新 API 响应上的这些状态。

我观察到只有 2 次重新渲染。

//API calling method:
    fetchData()
    {
     const response = await AuthAxios.getHomeData(); 
     dispatch({type: 'SET_HOME_DATA', data: response.data});
    
    }

//useReducer Code:
const initialStaes = {
  state1: null,
  state2: null,
   //.....More States 
  state27: null,
  state28: null
}

const HomeReducer = (state, action) => {
  switch (action.type) {
    case 'SET_HOME_DATA': {

      return {
        ...state,
        state1: (Data based on conditions),
        state2: !(some Conditions ),
        //....More states
        state27: false
       }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下 useReducer 的优点:

  1. 使用 useReducer 我减少了屏幕上重新渲染的次数,从而提高了应用程序的性能和流畅度。
  2. 我的屏幕本身的行数减少了。它提高了代码的可读性。