useEffect return 究竟是如何工作的?为什么代码会像它那样执行?
How exactly does useEffect's return work? Why is the code preforming like it does?
我正在练习 React Hooks,并且正在创建一个非常简单的秒表应用程序。目前,我的代码正在做我想做的事情,但我不明白它为什么会起作用。当我点击开始时,setTimeouts 运行 并不断更新时间状态。当我点击停止时,它会清除超时。当我没有明确告诉它时,为什么它会清除超时。此外,根据 react 文档,useEffect 中的 return 只会在组件卸载时 运行 。但是,我将 console.logs 放入其中并看到它 运行 是每次调用 useEffect 时的 returned 回调。最后,我删除了 returned 回调,发现当我点击停止时它实际上并没有清除超时。有人可以帮我分析一下吗?
import React, {useState, useEffect} from 'react';
function Stopwatch(){
const [time, setTime] = useState(0);
const [start, setStart] = useState(false);
useEffect(() => {
let timeout;
if (start) {
timeout = setTimeout(() => {setTime(currTime => currTime + 1);}, 1000);
}
return () => {
clearTimeout(timeout);
}
});
return(
<>
<div>{time}</div>
<button onClick={() => setStart(currStart => !currStart)}>{start ? "Stop" : "Start"}</button>
</>
)
}
export default Stopwatch
为什么当我没有明确告诉它时它会清除超时?
在你的实现中 useEffect
运行s 在每次重新渲染之后因为你没有指定依赖数组,所以如果你启动计时器然后在中间按下停止清理函数将进入 运行 并且最后的超时将被清除
事情是这样的,
组件挂载 -> useEffect
触发回调并 returns 一个函数 -> 当组件重新渲染时,执行返回的函数并且循环回到 运行设置 useEffect
回调。
您可能在文档中读到的内容有一个空的依赖项数组,它是 useEffect
的第二个参数
useEffect(() => {
console.log('will only run when the component mounts for the first time')
return () => {
console.log('will only run when the component unmounts')
}
}, []) // nothing inside the dependencies array, run this once
您的组件的更好实现将像这样
function Stopwatch(){
const [time, setTime] = useState(0)
const [start, setStart] = useState(false)
useEffect(() => {
// when start is false there is no reason to set up a timer or return a
// cleanup function so lets just exit early
if (!start) return
// start is true, set up the interval
const intervalId = setInterval(() => setTime(prevTime => prevTime + 1), 1000)
// return a cleanup function that will run only when start changes
// to false
return () => clearInterval(intervalId)
}, [start]) // run this effect only when start changes
const toggleStart = () => setStart(prevStart => !prevStart)
return(
<>
<div>{time}</div>
<button onClick={toggleStart}>{start ? "Stop" : "Start"}</button>
</>
)
}
我正在练习 React Hooks,并且正在创建一个非常简单的秒表应用程序。目前,我的代码正在做我想做的事情,但我不明白它为什么会起作用。当我点击开始时,setTimeouts 运行 并不断更新时间状态。当我点击停止时,它会清除超时。当我没有明确告诉它时,为什么它会清除超时。此外,根据 react 文档,useEffect 中的 return 只会在组件卸载时 运行 。但是,我将 console.logs 放入其中并看到它 运行 是每次调用 useEffect 时的 returned 回调。最后,我删除了 returned 回调,发现当我点击停止时它实际上并没有清除超时。有人可以帮我分析一下吗?
import React, {useState, useEffect} from 'react';
function Stopwatch(){
const [time, setTime] = useState(0);
const [start, setStart] = useState(false);
useEffect(() => {
let timeout;
if (start) {
timeout = setTimeout(() => {setTime(currTime => currTime + 1);}, 1000);
}
return () => {
clearTimeout(timeout);
}
});
return(
<>
<div>{time}</div>
<button onClick={() => setStart(currStart => !currStart)}>{start ? "Stop" : "Start"}</button>
</>
)
}
export default Stopwatch
为什么当我没有明确告诉它时它会清除超时?
在你的实现中 useEffect
运行s 在每次重新渲染之后因为你没有指定依赖数组,所以如果你启动计时器然后在中间按下停止清理函数将进入 运行 并且最后的超时将被清除
事情是这样的,
组件挂载 -> useEffect
触发回调并 returns 一个函数 -> 当组件重新渲染时,执行返回的函数并且循环回到 运行设置 useEffect
回调。
您可能在文档中读到的内容有一个空的依赖项数组,它是 useEffect
useEffect(() => {
console.log('will only run when the component mounts for the first time')
return () => {
console.log('will only run when the component unmounts')
}
}, []) // nothing inside the dependencies array, run this once
您的组件的更好实现将像这样
function Stopwatch(){
const [time, setTime] = useState(0)
const [start, setStart] = useState(false)
useEffect(() => {
// when start is false there is no reason to set up a timer or return a
// cleanup function so lets just exit early
if (!start) return
// start is true, set up the interval
const intervalId = setInterval(() => setTime(prevTime => prevTime + 1), 1000)
// return a cleanup function that will run only when start changes
// to false
return () => clearInterval(intervalId)
}, [start]) // run this effect only when start changes
const toggleStart = () => setStart(prevStart => !prevStart)
return(
<>
<div>{time}</div>
<button onClick={toggleStart}>{start ? "Stop" : "Start"}</button>
</>
)
}