简体   繁体   English

Reactjs - SetTimeout 与 state 更改重新渲染

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

I'm currently running into some issues whilst developing a Typescript React App.我目前在开发 Typescript React App 时遇到了一些问题。 Underneath is my current code..下面是我当前的代码..

But it's not behaving like I would want it to behave.但它的行为不像我想要的那样。 :) :)

So what I would like to achieve is that the data with getData(depth) runs whenever the component is being loaded and afterwards every 5 seconds.所以我想要实现的是,每当加载组件时,带有 getData(depth) 的数据就会运行一次,之后每 5 秒运行一次。

But when the Depth changes with the Dropdown.item buttons, it should re-render and the getData() should be ran with the new depth value that we just set in the state.. and keep on rendering afterwards with the new value...但是当 Depth 随 Dropdown.item 按钮发生变化时,它应该重新渲染,并且 getData() 应该使用我们刚刚在 state 中设置的新深度值运行。然后继续使用新值渲染。 .

I've been struggling with this, so any help is very much appreciated!!我一直在努力解决这个问题,所以非常感谢任何帮助!

Thank you!谢谢!

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;

That's because useEffect hook take a second params called dependency array , where this dependency array is what matter for the inner callback(inisde useEffect) to access the latest values you want.这是因为useEffect钩子需要第二个参数,称为dependency array ,其中这个依赖数组对于内部回调(inisde useEffect)访问你想要的最新值很重要。

So your are not being totally truthful here, if the inner callback depends on depth to be in its latest update then you should include it in the dependency array所以你在这里并不完全真实,如果内部回调取决于depth以使其最新更新,那么你应该将它包含在依赖数组中

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

that's for the depth but writing this code will immediately cause problems because for each new depth value the inner callback will be called and the setInterval will re-run again (causing many many...many of intervals).这是针对depth的,但是编写此代码会立即导致问题,因为对于每个新的depth值,内部回调将被调用,并且setInterval将再次重新运行(导致许多...许多间隔)。

To solve this you should avoid using setInterval alll together in hooks based code.要解决这个问题,您应该避免在基于hooks的代码中一起使用setInterval allll。

If having interval is really important I have a suggestion for you如果间隔真的很重要,我有一个建议给你


  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]);



Updated: After rading from Dan Abramov blog更新:Dan Abramov 博客评分后

you can find a better elegant solution that use setInterval and hooks您可以找到使用setIntervalhooks的更好的优雅解决方案

Making setInterval Declarative with React Hooks使用 React Hooks 使 setInterval 声明式

He made a custom hook called useInterval他制作了一个名为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]);
}

Usage be like用法就像

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

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

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