setInterval 和 setState 中的 useEffect Bug

useEffect Bug in setInterval and setState

我试过React的useEffect函数

useEffect(() => {
    setInterval(() => {
        const time =
            Date.parse(untilDeadline.deadline) - Date.parse(new Date());
        setuntilDeadline((prevValue) => {
            return {
                ...prevValue,
                seconds: Math.floor((time / 1000) % 60),
                minutes: Math.floor((time / 1000 / 60) % 60),
                hours: Math.floor((time / (1000 * 60 * 60)) % 24),
                days: Math.floor(time / (1000 * 60 * 60 * 24)),
            };
        });
    }, 1000);
}, []);

没有[]就崩溃了到底是为什么?

空数组表示只运行这一次。否则可能会导致重新渲染的无限循环。

你只需要 运行 一次,并且传递一个空数组告诉 useEffect useEffect 挂钩没有依赖关系,所以它不需要在每个渲染上重新 运行,并且 setInterval 会导致重新渲染。

If you want to run an effect and clean it up only once (on mount and unmount), you can pass an empty array ([]) as a second argument. This tells React that your effect doesn’t depend on any values from props or state, so it never needs to re-run. This isn’t handled as a special case — it follows directly from how the dependencies array always works.

If you pass an empty array ([]), the props and state inside the effect will always have their initial values. While passing [] as the second argument is closer to the familiar componentDidMount and componentWillUnmount mental model, there are usually better solutions to avoid re-running effects too often. Also, don’t forget that React defers running useEffect until after the browser has painted, so doing extra work is less of a problem.

https://reactjs.org/docs/hooks-effect.html

它崩溃的原因是您从未清理过 setInterval 调用。因此,每次组件重新呈现(例如通过 setuntilDeadline 调用)时,效果都会再次 运行。 [] 表示的是效果应该只 运行 挂载,然后在卸载时自行清理(因为它是一个空的依赖数组)。

此外,您应该清理 setInterval 调用而不考虑依赖项数组,以确保您没有内存泄漏和其他性能问题。

useEffect(() => {
    const intervalId = setInterval(() => {
        const time =
            Date.parse(untilDeadline.deadline) - Date.parse(new Date());
        setuntilDeadline((prevValue) => {
            return {
                ...prevValue,
                seconds: Math.floor((time / 1000) % 60),
                minutes: Math.floor((time / 1000 / 60) % 60),
                hours: Math.floor((time / (1000 * 60 * 60)) % 24),
                days: Math.floor(time / (1000 * 60 * 60 * 24)),
            };
        });
    }, 1000);
    return ()=>{
       clearInterval(intervalId);
    }
}, []);