为什么没有触发 useEffect?
Why is useEffect not being triggered?
我有一个应该是 运行 时钟的功能组件:
import React,{useState,useEffect} from 'react';
import 'materialize-css/dist/css/materialize.min.css';
import { parseTime } from '../../Utils/utils'
const MainClock = (props) => {
const [timeString, setTimeString] = useState(parseTime(new Date(), true));
function tick(){
console.log("TICK:" + timeString)
setTimeString(parseTime(new Date(), true));
};
useEffect(()=>{console.log("rendered!");setTimeout(tick,500);},[timeString]);
return (
<div>
<h5 className="center-align mainclock">{timeString}</h5>
</div>
);
}
export default MainClock;
但由于某种原因,它只被渲染了两次,控制台输出是:
rendered!
TICK:14:56:21
rendered!
TICK:14:56:22
为什么在第二次渲染后没有调用 useEffect?
欢迎任何帮助!
编辑:如果有帮助,这是 parseTime
:
const parseTime = (timeDate, withSeconds=false) =>{
let time = timeDate.getHours()<10 ? `0${timeDate.getHours()}`:`${timeDate.getHours()}`;
time+=":";
time+= timeDate.getMinutes()<10 ? `0${timeDate.getMinutes()}`:`${timeDate.getMinutes()}`;
if(withSeconds){
time+=":";
time+=timeDate.getSeconds()<10 ? `0${timeDate.getSeconds()}`:`${timeDate.getSeconds()}`;
}
return time;
}
问题是使用 setTimeout
和使用低延迟,即 500ms
超时。如果你记录 parseTime
的 return 值,你会注意到在两次调用之间,它 return 是同一个时间字符串,所以状态永远不会更新,导致组件永远不会 re-rendering 因此 useEffect
永远不会再次执行以设置另一个 setTimeout
.
解决方案
增加超时延迟或检查parseTime
函数的return值,如果与状态相同,则重新调用此函数。
另外,这里用setInterval
比setTimeout
更合适,因为setInterval
只需要调用一次,会重复调用tick
函数直到间隔被取消。如果您使用 setTimeout
,那么您将需要一次又一次地调用 setTimeout
以安排新的 tick
函数调用。
正如我上面指出的,这是短 setTimeout
计时值 - 500ms
的问题。
要使其工作,您需要使用 setInterval
const MainClock = (props) => {
const [timeString, setTimeString] = useState(parseTime(new Date(), true));
function tick(){
console.log("TICK:" + timeString)
setTimeString(parseTime(new Date(), true));
};
useEffect(() => {
setInterval(tick, 500);
}, []);
useEffect(()=>{console.log("rendered!");},[timeString]);
return (
<div>
<h5 className="center-align mainclock">{timeString}</h5>
</div>
);
}
我有一个应该是 运行 时钟的功能组件:
import React,{useState,useEffect} from 'react';
import 'materialize-css/dist/css/materialize.min.css';
import { parseTime } from '../../Utils/utils'
const MainClock = (props) => {
const [timeString, setTimeString] = useState(parseTime(new Date(), true));
function tick(){
console.log("TICK:" + timeString)
setTimeString(parseTime(new Date(), true));
};
useEffect(()=>{console.log("rendered!");setTimeout(tick,500);},[timeString]);
return (
<div>
<h5 className="center-align mainclock">{timeString}</h5>
</div>
);
}
export default MainClock;
但由于某种原因,它只被渲染了两次,控制台输出是:
rendered!
TICK:14:56:21
rendered!
TICK:14:56:22
为什么在第二次渲染后没有调用 useEffect?
欢迎任何帮助!
编辑:如果有帮助,这是 parseTime
:
const parseTime = (timeDate, withSeconds=false) =>{
let time = timeDate.getHours()<10 ? `0${timeDate.getHours()}`:`${timeDate.getHours()}`;
time+=":";
time+= timeDate.getMinutes()<10 ? `0${timeDate.getMinutes()}`:`${timeDate.getMinutes()}`;
if(withSeconds){
time+=":";
time+=timeDate.getSeconds()<10 ? `0${timeDate.getSeconds()}`:`${timeDate.getSeconds()}`;
}
return time;
}
问题是使用 setTimeout
和使用低延迟,即 500ms
超时。如果你记录 parseTime
的 return 值,你会注意到在两次调用之间,它 return 是同一个时间字符串,所以状态永远不会更新,导致组件永远不会 re-rendering 因此 useEffect
永远不会再次执行以设置另一个 setTimeout
.
解决方案
增加超时延迟或检查parseTime
函数的return值,如果与状态相同,则重新调用此函数。
另外,这里用setInterval
比setTimeout
更合适,因为setInterval
只需要调用一次,会重复调用tick
函数直到间隔被取消。如果您使用 setTimeout
,那么您将需要一次又一次地调用 setTimeout
以安排新的 tick
函数调用。
正如我上面指出的,这是短 setTimeout
计时值 - 500ms
的问题。
要使其工作,您需要使用 setInterval
const MainClock = (props) => {
const [timeString, setTimeString] = useState(parseTime(new Date(), true));
function tick(){
console.log("TICK:" + timeString)
setTimeString(parseTime(new Date(), true));
};
useEffect(() => {
setInterval(tick, 500);
}, []);
useEffect(()=>{console.log("rendered!");},[timeString]);
return (
<div>
<h5 className="center-align mainclock">{timeString}</h5>
</div>
);
}