为什么要在自定义react挂钩中使用setTimeout,是否必须将它包装在useEffect中?

时间:2019-12-04 13:53:56

标签: reactjs react-hooks

为什么需要为此自定义钩子将settimeout包装在useEffect钩子中?

function useWait (delay) {
  const [show, setShow] = React.useState(false)

  React.useEffect(() => {
    const id = window.setTimeout(() => {
      setShow(true)
    }, delay)

    return () => window.clearTimeout(id)
  }, [delay])

  return show
}

1 个答案:

答案 0 :(得分:1)

如果不将setTimeout或setInterval放入useEffect中,则每次重新发布组件时,它将重新初始化并且不会清除。

看下面的例子。每次您通过按按钮增加计数器时,父组件都会重新渲染,这会滴答所有孩子(包括我的setTimeout组件)。多次按下按钮,您将看到组件重新渲染几次,然后您将看到“超时完成”多次。

然后在下面我添加了一个带有useEffect的代码段,您将看到超时仅运行一次。

这能回答您的问题吗?

编辑:以下是一个代码框,可以尝试https://codesandbox.io/s/boring-liskov-4kjgm?fontsize=14&hidenavigation=1&theme=dark

无使用效果

import React, {useState} from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function App() {
  const [counter, increment] = useState(0);
  const doIncrement = () => increment(counter + 1);
  return (
    <div className="App">
      <Counter counter={counter} increment={doIncrement} />
      <OtherComponent />
    </div>
  );
}

const Counter = ({counter, increment}) => {
  return <button onClick={()=>increment()}>{counter}</button>
}

const OtherComponent = () => {
  console.log('I rerendered');
  const timeout = setTimeout(() => console.log('timeout finished'), 1000)
  return <h1> Hello world </h1>
}



const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

具有useEffect

import React, {useState, useEffect} from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function App() {
  const [counter, increment] = useState(0);
  const doIncrement = () => increment(counter + 1);
  return (
    <div className="App">
      <Counter counter={counter} increment={doIncrement} />
      <OtherComponent />
    </div>
  );
}

const Counter = ({counter, increment}) => {
  return <button onClick={()=>increment()}>{counter}</button>
}

const OtherComponent = () => {
  console.log('I rerendered');
  useEffect(() => {
     const timeout = setTimeout(() => console.log('timeout finished'), 1000)
     return () => clearTimeout(timeout)
  }, [])

  return <h1> Hello world </h1>
}



const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);