我不明白为什么当我使用setTimeout函数时,我的react组件开始到infinite 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]
  )

当前回答

您的计算机延迟是因为您可能忘记将空数组作为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/react@16.7.0-alpha.0/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script> <div id="app"></div>

其他回答

如果在其他人给出的例子中使用useEffect钩子来避免连续地将setInterval方法附加(挂载)和分离(卸载)到事件循环,您可能会转而使用useReducer。

想象这样一个场景:给定的秒和分,你要开始倒数…… 下面我们得到了一个减速器函数,它执行倒计时逻辑。

const reducer = (state, action) => {
  switch (action.type) {
    case "cycle":
      if (state.seconds > 0) {
        return { ...state, seconds: state.seconds - 1 };
      }
      if (state.minutes > 0) {
        return { ...state, minutes: state.minutes - 1, seconds: 60 };
      }
    case "newState":
      return action.payload;
    default:
      throw new Error();
  }
}

现在我们要做的就是在每个间隔中分派循环动作:

  const [time, dispatch] = useReducer(reducer, { minutes: 0, seconds: 0 });
  const { minutes, seconds } = time;

  const interval = useRef(null);
  
  //Notice the [] provided, we are setting the interval only once (during mount) here.
  useEffect(() => {
    interval.current = setInterval(() => {
      dispatch({ type: "cycle" });
    }, 1000);
    // Just in case, clear interval on component un-mount, to be safe.
    return () => clearInterval(interval.current);
  }, []);

  //Now as soon as the time in given two states is zero, remove the interval.
  useEffect(() => {
    if (!minutes && !seconds) {
      clearInterval(interval.current);
    }
  }, [minutes, seconds]);
  // We could have avoided the above state check too, providing the `clearInterval()`
  // inside our reducer function, but that would delay it until the next interval.

您的计算机延迟是因为您可能忘记将空数组作为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/react@16.7.0-alpha.0/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script> <div id="app"></div>

const[seconds, setSeconds] = useState(300);

function TimeOut() {
useEffect(() => {
    let interval = setInterval(() => {
        setSeconds(seconds => seconds -1);
    }, 1000);

    return() => clearInterval(interval);
}, [])

function reset() {
  setSeconds(300); 
} 

return (
    <div>
        Count Down: {seconds} left
        <button className="button" onClick={reset}>
           Reset
        </button>
    </div>
)
}

确保导入useState和useEffect。另外,添加在0处停止计时器的逻辑。

export const useTimeout = () => {
    const timeout = useRef();
    useEffect(
        () => () => {
            if (timeout.current) {
                clearTimeout(timeout.current);
                timeout.current = null;
            }
        },
        [],
    );
    return timeout;
};

您可以使用简单的钩子来共享超时逻辑。

const timeout = useTimeout();
timeout.current = setTimeout(your conditions) 

如果你的超时是在If结构中,试试这个:

useEffect(() => {
    let timeout;

    if (yourCondition) {
      timeout = setTimeout(() => {
        // your code
      }, 1000);
    } else {
      // your code
    }

    return () => {
      clearTimeout(timeout);
    };
  }, [yourDeps]);