仅当状态与当前值不同时,如何在反应挂钩中设置状态

时间:2020-04-09 23:30:57

标签: reactjs request react-hooks

我有以下代码

setInterval(() => {
             fetch(`/clusters?type=${type}`)
                .then((response) => response.json()
                  .then((responseBody) => {
                    if(clusters !== responseBody.members)
                        setClusters(responseBody.members);
                  }))
                .catch();
    }, 5000);

由于clusters在检查if(clusters !== responseBody.members) clusters始终为空时是异步设置的,因此哪种方法正确?我正在尝试这样做,以减少渲染次数,因为该请求每5秒发生一次

2 个答案:

答案 0 :(得分:1)

那是因为您所获得的状态已经过时。您可以做的是使用useRef创建一个引用,然后在另一个useEffect内用状态的当前值更新该引用。然后在获取数据后,使用ref将其与状态进行比较,如下所示:

function App() {
  const [clusters, setClusters] = useState([]);
  const clustersRef = useRef(clusters);

  useEffect(() => {
    clustersRef.current = clusters;
  });

  useEffect(() => {
    setInterval(() => {
      fetch(`/clusters?type=${type}`)
      .then((response) => response.json()
      .then((responseBody) => {
          if(clustersRef.current !== responseBody.members)
            setClusters(responseBody.members);
      }))
      .catch();
    }, 5000);
  }, []);
}

希望这会有所帮助:)

答案 1 :(得分:0)

您可以将一个函数传递给setClusters,该函数将当前状态作为参数。然后,您可以进行比较,如果有新内容,则返回新项,如果没有任何更改,则返回旧值。 React非常聪明,知道如果将state设置为 exact 相同的值,则不应重新渲染。

但是您还有另一个问题。如果您的状态没有改变,React已经足够聪明,不会重新渲染。但是您的状态 正在改变。您的api调用正在创建新的数据对象,这些数据对象无法直接与您的旧数据对象进行比较。

因此,您需要找出一种更好的方法来检测是否发生了更改。 ===!==不会告诉您两个数组具有相同的项目,它们会告诉您它们是否是相同的确切数组实例。

[1,2,3] === [1,2,3] //-> false

因此,您必须想出一种方法来判断您是否有两个包含相同内容的数组。一种方法是从旧数据和新数据创建一串id,然后进行比较。 (假设clusters是一个对象数组,上面有一些uniq id)。您创建一个可以与另一个值进行比较的单个值,以查看是否有任何更改。

setClusters(prevClusters => {
  const prevIds = prevClusters.map(member => member.id).sort().join('-')
  const newIds = responseBody.members.map(member => member.id).sort().join('-')

  if (newIds === prevIds) {
    return prevClusters // nothing has changed, return previous value
  } else {
    return responseBody.members // return new values.
  }
})