繁体   English   中英

Reactjs - SetTimeout 与 state 更改重新渲染

[英]Reactjs - SetTimeout with state change re-render

我目前在开发 Typescript React App 时遇到了一些问题。 下面是我当前的代码..

但它的行为不像我想要的那样。 :)

所以我想要实现的是,每当加载组件时,带有 getData(depth) 的数据就会运行一次,之后每 5 秒运行一次。

但是当 Depth 随 Dropdown.item 按钮发生变化时,它应该重新渲染,并且 getData() 应该使用我们刚刚在 state 中设置的新深度值运行。然后继续使用新值渲染。 .

我一直在努力解决这个问题,所以非常感谢任何帮助!

谢谢!

import React, { useState, useEffect } from "react";

const chart = () => {
  const [depth, setDepth] = useState(20);
  const [chartData, setChartData] = useState({})

//Getting the data when the app initially renders and should keep rendering every 5 seconds after that.
//When the value of the depth changes, we should stop getting the data with the old depth //value and should start a new interval of 5 seconds and just keep running with the new //depth value
//When first entering the app, this should run immediately with the initial depth state //(20)

  useEffect(() => {
    const interval = setInterval(() => {
     //this code is not the actual code, just an example of what is running
      const data = getData(depth)
     //just fetched the new data, now setting it.. 
      setChartData(data)
    }, 5000);
    return () => clearInterval(interval);
  }, []);

  return (
<div>
  <div>
   <DropdownButton id="dropdown-basic-button" title="Depth Percentage">
    <Dropdown.Item onClick={() => setDepth(5)}>5%</Dropdown.Item>
    <Dropdown.Item onClick={() => setDepth(20)}>20%</Dropdown.Item>
   </DropdownButton>
  </div>
  <div>
   //Rendering the Chart here....
  </div>
</div>
  );
};

export default chart;

这是因为useEffect钩子需要第二个参数,称为dependency array ,其中这个依赖数组对于内部回调(inisde useEffect)访问你想要的最新值很重要。

所以你在这里并不完全真实,如果内部回调取决于depth以使其最新更新,那么你应该将它包含在依赖数组中

useEffect(() => { ... }, [ depth ]);

这是针对depth的,但是编写此代码会立即导致问题,因为对于每个新的depth值,内部回调将被调用,并且setInterval将再次重新运行(导致许多...许多间隔)。

要解决这个问题,您应该避免在基于hooks的代码中一起使用setInterval allll。

如果间隔真的很重要,我有一个建议给你


  const [intervalCount, setIntervalCount] = useState(0);
  const [depth, setDepth] = useState(20);
  const [chartData, setChartData] = useState({})


  useEffect(() => {
    // when depth change re-fetch data and set it
    const data: any = getData(depth);
    setChartData(data);
  }, [depth])


  // simulate set interval behavior 
  // each 5 s this function will be re-invoked
  useEffect(() => {

    // re-fetch data and set it
    const data: any = getData(depth);
    setChartData(data);

    // wait 5 s before cause a re-render
    setTimeout(() => {
      setIntervalCount(count => count + 1);
    }, 5000);

  }, [intervalCount]);



更新:Dan Abramov 博客评分后

您可以找到使用setIntervalhooks的更好的优雅解决方案

使用 React Hooks 使 setInterval 声明式

他制作了一个名为useInterval的自定义钩子

function useInterval(callback, delay) {
  const savedCallback = useRef();

  // Remember the latest callback.
  useEffect(() => {
    savedCallback.current = callback;
  }, [callback]);

  // Set up the interval.
  useEffect(() => {
    function tick() {
      savedCallback.current();
    }
    if (delay !== null) {
      let id = setInterval(tick, delay);
      return () => clearInterval(id);
    }
  }, [delay]);
}

用法就像

  useInterval(() => {
    // Your custom logic here
    setCount(count + 1);
  }, 1000);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM