簡體   English   中英

SetInterval沒有顯示更新狀態

[英]SetInterval is not showing updated state

在調用setInterval函數之前,我已將狀態設置為true。 但是,即使用狀態的新值觸發了useEffect鈎子,也沒有反映在setInterval函數中。

在此處輸入圖片說明 此處的代碼沙箱: https//jsfiddle.net/6e05tc2L/3/

let interval;
const Component = () => {
  React.useEffect(() => {
    console.log('State updated to', state);
  });
  const [state, setState] = React.useState(false);
  const on = () => {
    setState(true);
    interval = setInterval(() => {
      console.log(state);
    }, 1000);
    }
  const off = () => {
    setState(false);
    clearInterval(interval);
  }
  const toggle = () => state ? off() : on()

  return (<div>
    <button onClick={toggle}>Toggle State</button>
   </div>);
}

ReactDOM.render(
  <Component />,
  document.getElementById('container')
);

一旦更新,它不應該使用狀態的新值嗎?

傳遞給useEffect的函數內部的值在每個渲染上都會刷新,因為useEffect使用傳遞給它的函數的新定義。

但是傳遞給setInterval的函數只定義了一次,並且關閉了狀態的舊值。 尚未更新。

使用鈎子進行閉包是棘手的,但是要意識到的是useEffect為每個渲染創建一個新函數,因此每次函數關閉一個新的狀態值時都會創建一個新函數。

然后,訣竅是在useEffect自身內部調用與setInterval相關的代碼,該函數本身取決於state的變化值

React.useEffect(() => {
  if(state) {

    interval = setInterval(() => {
      console.log(state);
    }, 1000);
  } else {
    clearInterval(interval);
  }

}, [state]);

或者,最好使用useInterval掛鈎,該掛鈎為您處理這些詳細信息。

setInterval始終可以訪問組件的第一個渲染的值,因為傳遞給setInterval的函數會圍繞該值關閉,並且永遠不會重新聲明。 您可以使用自定義鈎子解決此問題:

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

  useEffect(() => {
    savedCallback.current = callback;
  });

  useEffect(() => {
    function tick() {
      savedCallback.current();
    }

    let id = setInterval(tick, delay);
    return () => clearInterval(id);
  }, [delay]);
}

該實現和對React Hooks與setInterval之間不匹配的全面解釋是來自React貢獻者之一Dan Abramov的《使用React Hooks進行setInterval聲明》

如果要在狀態更改時重新加載組件,則應按以下方式創建useEffect。

React.useEffect(() => {
    console.log('State updated to', state);
}, [state]);

您創建的方式與componentDidMount()相同,只是將數組作為第二個參數,就像componentDidUpdate()具有依賴項。 因此,只要您的狀態發生變化,您的組件就會重新渲染。

要解決setTimeout的無窮大調用,您可以在創建函數的地方執行此操作

React.useCallback(() => {
    setInterval(() => {
        console.log(state);
    }, 1000);
})

使用此React將會知道您只想創建一次此函數。

我不是ReactJS專家,但是我想您正在記錄的state不會刷新,因為它被聲明一次且從未刷新過。 如果React.useState(false)是為您提供狀態的方法,則應在interval函數中使用它。

這是我要解釋的示例:

 const object = { value: false } const notRefreshed = object.value // here we are copying the value const interval = setInterval(() => { const refreshed = object.value // here we are using the reference to copy the latest value console.log("refreshed", refreshed) console.log("notRefreshed", notRefreshed) }, 500) setTimeout(() => object.value = true, 1600) setTimeout(() => clearInterval(interval), 2600) 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM