【问题标题】:useState() in react does not update the data - is this the sort() issue?反应中的 useState() 不会更新数据 - 这是 sort() 问题吗?
【发布时间】:2020-07-03 11:59:48
【问题描述】:

当我在网站加载后单击按钮对有关国家/地区的数据进行排序时,数据显示正确。但是当我想按不同的值再次对其进行排序时,数据不会更新,状态也不会更新,但是,该功能运行良好,因为我可以看到控制台中的结果已正确排序。这种奇怪行为的原因是什么?感谢您的宝贵时间。

 function AllCountries({ countries }) {
  const [sortedCountries, setSortedCountries] = useState([]);

  useEffect(() => {
      console.log(sortedCountries)
  }, [sortedCountries])

  const sortResults = (val) => {
    let sortedResults = countries.sort((a, b) => {
      if (val === "deaths") {
        return b.TotalDeaths - a.TotalDeaths;
      } else if (val === "cases") {
        return b.TotalConfirmed - a.TotalConfirmed;
      } else if (val === "recovered") {
        return b.TotalRecovered - a.TotalRecovered;
      }
    });
    console.log(sortedResults);
    setSortedCountries(sortedResults);
  };

  return (
    <div className="all-container">
      <p>Sort countries by the highest number of:</p>
      <button onClick={() => sortResults("deaths")}>Deaths</button>
      <button onClick={() => sortResults("cases")}>Cases</button>
      <button onClick={() => sortResults("recovered")}>Recoveries</button>
      <ul className="all-countries">
        {sortedCountries.map((country, key) => {
          return <li key={key}>{country.Country}</li>;
        })}
      </ul>
    </div>
  );
}

export default AllCountries;

【问题讨论】:

    标签: javascript reactjs react-hooks use-state


    【解决方案1】:

    让 sortedResults = countries.sort

    这一行正在对国家属性进行排序并将 sortedResults 设置为该指针

    让我们假设指针保存在 mem |0001|为简单起见

    第一次点击后,函数被触发,prop 被排序,sortedResults 通过 setSortedCountries 设置(设置状态)。

    这会触发你想要的渲染,因为之前的状态是未定义的,现在状态指向 |0001|

    当您的函数再次运行时,排序函数将触发,并在 |0001| 上工作并返回——你猜对了——|0001|但是使用新的排序数组。

    当你第二次设置状态时,实际上并没有改变任何状态,因为之前的国家是 |0001|而你想改成的国家是|0001|

    那么先生,我们能做些什么呢?

    首先,我需要您考虑一下这个问题,想一想如何解决这个问题并尝试应用一些更改。

    您可以尝试将国家属性复制到具有相同值的新数组指针,然后对其进行排序,然后将 sortedCountries 状态设置为该列表。

    这有意义吗?

    顺便说一句,这也是出于类似的原因,如果您尝试直接在新对象状态上设置状态,则新对象状态将与您设置的完全相等。这里没有任何真正的魔法。 React 不会自动合并你之前的对象状态和新的对象状态,除非你明确告诉它这样做。

    从某种意义上说,您已经告诉 react 检查两个州之间的差异,一个旧国家和一个新国家(在 Vdom 的幕后),但是对于反应,这两个国家没有区别。并且由于这两个对象状态没有区别,因此不会有实际的 DOM 变化。

    你设置一个指针两次因此不会产生实际的变化。

    因此,您必须将 state 设置为具有新值的实际新指针,以便 react 虚拟 dom 可以比较两个州(以前的国家/地区列表)和新的国家/地区列表。

    希望有帮助

    -

    【讨论】:

    • 我很想知道覆盖 shouldUpdate 并始终返回 true 是否也会产生相同的效果。
    【解决方案2】:

    Array.sort() 方法不返回新引用,它返回相同的引用。所以我假设在sortedCountries state 中存储了相同的 props.countries 引用,这就是为什么第二个按钮单击不设置状态(它是相同的引用),我可以给你简单的解决方案只需更改这一行 setSortedCountries(sortedResults)在这种情况下,使用此setSortedCountries([...sortedResults]),sortedResults 的副本将传递给setSortedCountries(新参考)。

    【讨论】:

    • 仍在变异国家,这是一个非常糟糕的主意,因为它是一个道具(组件不应该改变他们的道具)。最好在源头解决你的突变:let sortedResults = [...countries].sort( 现在设置状态不需要改变:setSortedCountries(sortedResults)
    • 谢谢您的建议,我按照您说的做了,但我不明白。变异是什么意思?
    • 这是变异的意思,传递的 props.countries 将被更改,你必须避免更改道具,因为如果有人在其他地方使用相同的道具引用,它也会在那里被更改,所以正如@HMR 提到的最好先复制props.countries,然后调用.sort方法。
    【解决方案3】:

    这在 React 中有点问题,另一个解决方案是使用 useReducer 代替。如下:

    function reducer(state, action) {
       return [...state, ...action];
    }
     function AllCountries({ countries }) {
      const [sortedCountries, setSortedCountries] = useReducer(reducer, []);
    
      useEffect(() => {
          console.log(sortedCountries)
      }, [sortedCountries])
    
      const sortResults = (e, val) => {
          e.preventDefault();
        let sortedResults = countries.sort((a, b) => {
          if (val === "deaths") {
            return b.TotalDeaths - a.TotalDeaths;
          } else if (val === "cases") {
            return b.TotalConfirmed - a.TotalConfirmed;
          } else if (val === "recovered") {
            return b.TotalRecovered - a.TotalRecovered;
          }
        });
        console.log(sortedResults);
        setSortedCountries(sortedResults);
      };
    
      return (
        <div className="all-container">
          <p>Sort countries by the highest number of:</p>
          <button onClick={(e) => sortResults(e, "deaths")}>Deaths</button>
          <button onClick={(e) => sortResults(e, "cases")}>Cases</button>
          <button onClick={(e) => sortResults(e, "recovered")}>Recoveries</button>
          <ul className="all-countries">
            {sortedCountries.map((country, key) => {
              return <li key={key}>{country.Country}</li>;
            })}
          </ul>
        </div>
      );
    }
    
    export default AllCountries;
    

    【讨论】:

      猜你喜欢
      • 2020-03-23
      • 1970-01-01
      • 2023-02-06
      • 1970-01-01
      • 2020-10-28
      • 1970-01-01
      • 1970-01-01
      • 2021-04-19
      • 1970-01-01
      相关资源
      最近更新 更多