我正在练习react钩子,并且正在创建一个非常简单的秒表应用。当前,我的代码正在完全按照我想要的去做,但是我不明白为什么会起作用。当我点击开始时,setTimeouts运行并不断更新时间状态。当我按下停止按钮时,它将清除超时。当我没有明确告知超时时,为什么清除超时。另外,根据react docs,仅当组件卸载时,useEffect中的return才会运行。但是,我将console.logs放入其中,发现每次调用useEffect时,它都会运行返回的回调。最后,我删除了返回的回调,发现当我按下Stop时,它实际上并没有清除超时。有人可以帮我剖析吗?
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
答案 0 :(得分:0)
当我没有明确告诉它时为什么清除超时?
在您的实现useEffect
中,由于未指定依赖项数组,因此在运行useEffect
后运行,因此,如果启动计时器,然后在中间按下Stop键,则清理功能将运行,并且最后的超时将被清除
它是这样的,
组件挂载-> 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>
</>
)
}
这样更好地实现组件
export interface RestCriteria {
page: number,
pageSize: number
}
export interface ResponseMetaData {
page: number,
pageSize: number,
totalRecords: number
}
export interface QueryResponse {
metaData: ResponseMetaData,
records: []
}
export interface RestService {
query: (criteria: RestCriteria) => QueryResponse,
}
class Rest implements RestService
{
query: (criteria: RestCriteria) => { //why is this not valid??
return {
metaData: {
page: 1,
pageSize: 1,
totalRecords: 1
},
records: []
}
};
}
export default Rest;