web-dev-qa-db-ja.com

Reactフック-タイムアウトと間隔をクリアする正しい方法

setTimeout関数を使用すると、reactコンポーネントが無限のconsole.logを開始する理由がわかりません。すべてが機能しているが、PCは地獄のように遅れ始める。私の状態を変更するタイムアウトで機能し、そのコンポーネントを再レンダリングし、新しいタイマーを設定するなどと言う人もいます。今、私はそれが正しいことをクリアする方法を理解する必要があります。

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]
  )
14
RTW

useEffectのReturn関数は、useEffectが実行されるたびに実行されます(コンポーネントマウントでの最初の実行を除く)。新しいuseEffectが実行されるたびに、古い実行が削除されるため、それについて考えてください。

これは、タイムアウトまたは間隔を使用およびクリアする有効な方法です。

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>
}

外部のどこかでタイムアウトまたは間隔をクリアする必要がある場合:

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>
}

キューを管理する必要がある場合(タイマー/インターバル内の状態を変更する)、 ここで答えを探してください

30
RTW

useEffectの2番目の引数として空の配列を渡すのを忘れて、コールバック内で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>
4
Yangshun Tay