【问题标题】:react 18 useState and useEffect re-renderingreact 18 useState 和 useEffect 重新渲染
【发布时间】:2022-06-18 02:48:47
【问题描述】:

告诉我为什么更改用户状态后页面上的重新渲染不起作用 再次单击页面后会发生更改,而不是立即发生。

  useEffect(() => {
    const sortfdb = Datadb.sort((a,b) => b.count - a.count);
    console.log(sortfdb)
    setDatadb(sortfdb);
    console.log(Datadb)
  },[Datadb])

我在页面上有一个字段,我将添加一个数字,它写入 useState([]),当更改 useState 时,它​​应该对它们进行排序。但这并没有发生。只有当我添加一个新号码时才会发生这种情况。

useEffect,它捕获更改、工作并在控制台中按应有的方式显示所有内容,但不想立即在页面上更改它 它在 React 17 中运行良好,但现在不行。我不知道出了什么问题


更新

我意识到我的错误,我必须提供一个数组排序

setDatadb(el=>[...el].sort((a,b) => b.count - a.count));

但是现在它会无限期地抛出错误,因为渲染是不断发生的

next-dev.js?3515:25 Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.

【问题讨论】:

  • React 18 有一些差异所以推荐使用 React 17
  • 这点我已经明白了,不过18号正式出老版我看不出有什么意义
  • 您不应该在 useEffect 中使用 setDatadb 并将 Datadb 设置为依赖项。会导致死循环。

标签: reactjs react-hooks


【解决方案1】:
next-dev.js?3515:25 Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.

不应在 useEffect 中将值更新到状态。您必须在外部创建一个函数并更新状态值。

发生这种情况是因为一旦你更新了一个状态,状态的引用就会改变并且组件会重新渲染。再次因为参考被改变了。 useEffect 将被再次调用,这种情况会无限发生,并且在一定程度上反应停止。

【讨论】:

    【解决方案2】:

    设置状态是异步的,当console.log(Datadb)被执行时,setDatadb(sortfdb)还没有完成。即使在 React 18 之前,这也是预期的行为。但是,状态会改变,你不能控制台记录它,因为它是异步的......

    【讨论】:

    • 我了解状态是如何工作的,只是之前在useEffect中我截取了useState的变化,并根据需要再次更改。立即出现了视觉上的变化。
    • 我的意思是你不能在 setState 之后 console.log 状态,因为你仍然会记录旧状态(因为 setState 是异步的)。
    【解决方案3】:

    错误是sort没有提供数组,解决了这样的问题:

    setDatadb(el=>[...el].sort((a,b) => b.count - a.count));
    

    我从 useEffect 中删除了检查,并在添加新变量后立即将其移动。

    不再有无限循环,在 useEffect 中,最重要的是,添加新变量后,它对值进行排序

    【讨论】:

      【解决方案4】:

      问题

      您正在使用Array.prototype.sort 改变当前状态。

      sort() 方法就地对数组的元素进行排序,返回 排序后的数组

      此外,Datadb 状态数组引用永远不会改变,因此 React 放弃重新渲染,因为它使用浅引用相等检查作为协调过程的一部分。

      useEffect(() => {
        const sortfdb = Datadb.sort((a, b) => b.count - a.count); // <-- mutation
        console.log(sortfdb); // <-- sortfdb reference to Datadb state
        setDatadb(sortfdb);   // <-- state reference never changed, no rerender!
        console.log(Datadb);
      }, [Datadb]);
      

      当您修复数组引用问题时,该问题将成为挂钩依赖问题。

      useEffect(() => {
        // update dependency, render loop!
        setDatadb(el => [...el].sort((a, b) => b.count - a.count));
      }, [Datadb]);
      

      不要无条件地更新钩子的依赖数组中的值,因为这将触发 React 的重新渲染,并且钩子再次运行,将更新排入队列并触发另一个重新渲染,重复令人作呕。这是 React 警告的渲染循环错误。

      解决方案

      如果您需要在useEffect 中对Datadb 状态进行排序,则不要使用Datadb 状态作为钩子的依赖项。使用空的依赖数组或其他值来“触发”效果。

      例子:

      const [sortData, setSortData] = React.useState(false);
      
      useEffect(() => {
        if (sortData) {
          setDatadb(data => data.slice().sort((a, b) => b.count - a.count));
          setSortData(false);
        }
      }, [sortData]);
      
      ...
      
      // some event handler
      setSortData(true); // to trigger sorting
      

      如果您只想对Datadb 状态进行排序以响应事件,那么您可能根本不需要useEffect 挂钩。您可以/应该直接将状态更新加入队列以对 that 处理函数中的数据进行排序。

      例子:

      const sortDataByCount = () => {
        setDatadb(data => data.slice().sort((a, b) => b.count - a.count));
      };
      
      ...
      
      <button type="button" onClick={sortDataByCount}>
        Sort by Count
      </button>
      

      【讨论】:

        猜你喜欢
        • 2020-04-01
        • 1970-01-01
        • 2021-11-26
        • 1970-01-01
        • 2021-09-14
        • 2020-08-15
        • 1970-01-01
        • 2020-08-06
        • 2021-02-17
        相关资源
        最近更新 更多