React hooks - 清除超时和间隔的正确方法

问题描述 投票:8回答:2

我不明白为什么当我使用setTimeout函数时,我的反应组件启动无限的console.log。一切正常,但PC开始落后于地狱。有些人说超时功能会改变我的状态和rerender组件,设置新的计时器等等。现在我需要了解如何清除它是正确的。

export default function Loading() {
  // if data fetching is slow, after 1 sec i will show some loading animation
  const [showLoading, setShowLoading] = useState(true)
  let timer1 = setTimeout(() => setShowLoading(true), 1000)

  console.log('this message will render  every second')
  return 1
}

清除不同版本的代码无助于:

const [showLoading, setShowLoading] = useState(true)
  let timer1 = setTimeout(() => setShowLoading(true), 1000)
  useEffect(
    () => {
      return () => {
        clearTimeout(timer1)
      }
    },
    [showLoading]
  )
javascript reactjs settimeout react-hooks
2个回答
24
投票

每次运行useEffect时,useEffect中的返回函数都会运行(除了首次运行组件装载)。想想它每次有新的useEffect执行时,旧的被删除。

This is a working way to use and clear timeouts or intervals:

export default function Loading() {   
     const [showLoading, setShowLoading] = useState(false)

     useEffect(
        () => {
          let timer1 = setTimeout(() => setShowLoading(true), 1000)

          // this will clear Timeout when component unmont like in willComponentUnmount
          return () => {
            clearTimeout(timer1)
          }
        },
        [] //useEffect will run only one time
           //if you pass a value to array, like this [data] than clearTimeout will run every time this value changes (useEffect re-run)
      )

 return showLoading && <div>I will be visible after ~1000ms</div>
}

If you need to clear timeouts or intervals somewhere outside:

export default function Loading() {   
     const [showLoading, setShowLoading] = useState(false)

     const timerToClearSomewhere = useRef(false) //now you can pass timer to another component

     useEffect(
        () => {
          timerToClearSomewhere.current = setInterval(() => setShowLoading(true), 1000)

          return () => {
            clearInterval(timerToClearSomewhere.current)
          }
        },
        []
      )

  //here we can imitate clear from somewhere else place
  useEffect(() => {
    setTimeout(() => clearInterval(timerToClearSomewhere.current), 15000)
  }, [])

 return showLoading && <div>I will be visible after ~1000ms</div>
}

4
投票

你的计算机是滞后的,因为你可能忘了传入空数组作为useEffect的第二个参数,并在回调中触发了setState。这导致无限循环,因为useEffect在渲染时触发。

这是一种在挂载时设置计时器并在卸载时清除计时器的工作方式:

function App() {
  React.useEffect(() => {
    const timer = window.setInterval(() => {
      console.log('1 second has passed');
    }, 1000);
    return () => { // Return callback to run on unmount.
      window.clearInterval(timer);
    };
  }, []); // Pass in empty array to run useEffect only on mount.

  return (
    <div>
      Timer Example
    </div>
  );
}

ReactDOM.render(
  <div>
    <App />
  </div>,
  document.querySelector("#app")
);
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

<div id="app"></div>
© www.soinside.com 2019 - 2024. All rights reserved.