组件中useState多次调用状态更新程序会导致多次重新渲染

JavaScript React.js

老丝

2020-03-18

我第一次尝试使用React钩子,直到我意识到当我获取数据并更新两个不同的状态变量(数据和加载标志)时,我的组件(数据表)都会呈现两次,即使两次调用都看起来不错状态更新程序发生在同一功能中。这是我的api函数,它将两个变量都返回给我的组件。

const getData = url => {

    const [data, setData] = useState(null);
    const [loading, setLoading] = useState(true);

    useEffect(async () => {

        const test = await api.get('/people')

        if(test.ok){
            setLoading(false);
            setData(test.data.results);
        }

    }, []);

    return { data, loading };
};

在普通的类组件中,您只需调用一次即可更新状态,该状态可以是一个复杂的对象,但“钩子”似乎是将状态拆分为多个较小的单元,其副作用似乎是多次重做。分别更新时呈现。任何想法如何减轻这种情况?

第2099篇《组件中useState多次调用状态更新程序会导致多次重新渲染》来自Winter(https://github.com/aiyld/aiyld.github.io)的站点

3个回答
阳光Stafan 2020.03.18

如果您使用的是第三方挂钩,并且无法将状态合并到一个对象中或无法使用useReducer,则解决方案是使用:

ReactDOM.unstable_batchedUpdates(() => { ... })

Dan Abramov 在这里推荐

看这个例子

Jim凯 2020.03.18

一些补充答案https://stackoverflow.com/a/53575023/121143

凉!对于那些打算使用此钩子的人,可以用某种健壮的方式编写它,以将函数用作参数,例如:

const useMergedState = initial => {
  const [state, setState] = React.useState(initial);
  const setMergedState = newState =>
    typeof newState == "function"
      ? setState(prevState => ({ ...prevState, ...newState(prevState) }))
      : setState(prevState => ({ ...prevState, ...newState }));
  return [state, setMergedState];
};

更新:优化版本,当传入的部分状态未更改时,状态不会被修改。

const shallowPartialCompare = (obj, partialObj) =>
  Object.keys(partialObj).every(
    key =>
      obj.hasOwnProperty(key) &&
      obj[key] === partialObj[key]
  );

const useMergedState = initial => {
  const [state, setState] = React.useState(initial);
  const setMergedState = newIncomingState =>
    setState(prevState => {
      const newState =
        typeof newIncomingState == "function"
          ? newIncomingState(prevState)
          : newIncomingState;
      return shallowPartialCompare(prevState, newState)
        ? prevState
        : { ...prevState, ...newState };
    });
  return [state, setMergedState];
};
LGil 2020.03.18

react-hooks中的批处理更新 https://github.com/facebook/react/issues/14259

如果从基于React的事件中触发状态更新,例如按钮单击或输入更改,React当前将批处理状态更新。如果更新是在React事件处理程序之外触发的,例如异步调用,它将不会批量更新。

问题类别

JavaScript Ckeditor Python Webpack TypeScript Vue.js React.js ExpressJS KoaJS CSS Node.js HTML Django 单元测试 PHP Asp.net jQuery Bootstrap IOS Android