簡體   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