当前位置: 首页 > 面试题库 >

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

上官鸿祯
2023-03-14
问题内容

我第一次尝试使用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 };
};

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


问题答案:

您可以将loading状态和data状态组合为一个状态对象,然后可以进行一次setState调用,并且只会有一个渲染。

注意:setStatein类组件不同,setStatereturn from
useState不会合并具有现有状态的对象,而是会完全替换该对象。如果要进行合并,则需要读取以前的状态,然后自己将其与新值合并。请参考文档。

在您确定性能问题之前,我不必担心过度调用渲染。呈现(在React上下文中)和将虚拟DOM更新提交到实际DOM是不同的事情。这里的渲染是指生成虚拟DOM,而不是更新浏览器DOM。React可能会批量setState调用并用最终的新状态更新浏览器DOM。

const {useState, useEffect} = React;



function App() {

  const [userRequest, setUserRequest] = useState({

    loading: false,

    user: null,

  });



  useEffect(() => {

    // Note that this replaces the entire object and deletes user key!

    setUserRequest({ loading: true });

    fetch('https://randomuser.me/api/')

      .then(results => results.json())

      .then(data => {

        setUserRequest({

          loading: false,

          user: data.results[0],

        });

      });

  }, []);



  const { loading, user } = userRequest;



  return (

    <div>

      {loading && 'Loading...'}

      {user && user.name.first}

    </div>

  );

}



ReactDOM.render(<App />, document.querySelector('#app'));


<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>

<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>

<div id="app"></div>

另类-编写您自己的状态合并钩子

const {useState, useEffect} = React;



function useMergeState(initialState) {

  const [state, setState] = useState(initialState);

  const setMergedState = newState =>

    setState(prevState => Object.assign({}, prevState, newState)

  );

  return [state, setMergedState];

}



function App() {

  const [userRequest, setUserRequest] = useMergeState({

    loading: false,

    user: null,

  });



  useEffect(() => {

    setUserRequest({ loading: true });

    fetch('https://randomuser.me/api/')

      .then(results => results.json())

      .then(data => {

        setUserRequest({

          loading: false,

          user: data.results[0],

        });

      });

  }, []);



  const { loading, user } = userRequest;



  return (

    <div>

      {loading && 'Loading...'}

      {user && user.name.first}

    </div>

  );

}



ReactDOM.render(<App />, document.querySelector('#app'));


<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>

<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>

<div id="app"></div>


 类似资料:
  • 我第一次尝试React钩子,一切似乎都很好,直到我意识到当我获取数据并更新两个不同的状态变量(数据和加载标志)时,我的组件(数据表)会呈现两次,尽管对状态更新器的两次调用都发生在同一个函数中。下面是我的api函数,它将两个变量都返回到我的组件中。 在普通的类组件中,您只需调用一次来更新状态,状态可能是一个复杂的对象,但“挂钩方式”似乎是将状态拆分为更小的单元,其副作用似乎是在单独更新时多次重新呈现

  • 问题内容: 我这里有一些简单的代码 每次单击按钮,控制台上都会显示2条日志,指示该组件呈现两次。 这是一个codeandbox链接,可以尝试一下。 问题答案: 呈现您的App组件的原因是在其中导致代码在严格模式下运行,并且在严格模式下,控制台显示两次,因为每个功能在开发模式下均运行两次 根据react docs: 严格模式无法自动为您检测副作用,但可以通过使其更具确定性来帮助您发现它们。这是通过有

  • 问题内容: 我正在构建一个PhotoViewer,当用户向左或向右按​​下时可以更改照片。我正在使用React,Redux,react-router和react- router- redux。当用户按下向左或向右按钮时,我会做两件事,我使用来更新网址,并调度一个操作来更新当前查看的照片。我正在订阅状态更改以进行调试。 以上每一行都会触发新的状态更改。因为我更新了,所以分派操作会更新存储,而更新UR

  • 我有一个带有两组按钮(功能和目标)的界面。当我点击一个按钮时,我希望它从一个团队转到另一个团队。我正在用react和redux实现这一点。我唯一的问题是,当状态更新并且我成功地记录了更新的状态时,除非我使用forceUpdate(),否则组件不会更新。我不明白的是,既然状态更新成功,组件不应该自动重新渲染吗? 一些js 正如您所看到的,当我单击一个按钮时,我触发updateLists函数,该函数将

  • 我正在学习如何应对,我整天都在试图找到解决问题的办法,但都没有成功。然后决定在这里提出我的第一个问题。 我有子组件,包括React-Datepicker组件和单独的“第二天”和“前一天”按钮来更改选定的日期。 SelectedDate存储在父组件的状态中。 我试图从子组件更新父组件的状态,当状态更新时,子组件应该重新呈现,因为该状态作为道具传递给同一个子组件。 我已设法从child更改父状态,但子

  • 我有一个组件,它需要获取数据,将其设置为state,然后将其传递给子级。一些数据还需要在上下文中设置。我的问题是,使用useEffect,一旦调用API,它将为我需要执行的每个setvalue()函数重新呈现。我已经尝试传递useffect一个空的[]数组,由于状态正在改变,仍然得到相同数量的重新渲染。此时数组包含集合。。。用于防止eslint抛出警告的函数。 有没有更好的方法来避免如此多的重新渲