Javascript 用钩子建造一个时钟
我正在制作一个计时时钟,只是一个练习(我知道有更好的方法) 我的问题是,当一分钟被添加时,“addMinute”似乎会运行两次,我一辈子都不知道如何或为什么 下面是codesandbox的演示: 下面是代码一览表: (请注意,计数器最多只能计数3次,计数速度更快;这仅用于测试目的)Javascript 用钩子建造一个时钟,javascript,reactjs,Javascript,Reactjs,我正在制作一个计时时钟,只是一个练习(我知道有更好的方法) 我的问题是,当一分钟被添加时,“addMinute”似乎会运行两次,我一辈子都不知道如何或为什么 下面是codesandbox的演示: 下面是代码一览表: (请注意,计数器最多只能计数3次,计数速度更快;这仅用于测试目的) const Clock=(道具)=>{ 常量[秒,设置秒]=使用状态(0) const[minutes,setMinutes]=useState(0) 常数[hours,setHours]=useState(0) 常
const Clock=(道具)=>{
常量[秒,设置秒]=使用状态(0)
const[minutes,setMinutes]=useState(0)
常数[hours,setHours]=useState(0)
常数addHour=()=>{
设定小时数(p=>p+1)
}
常数addMinute=()=>{
设置分钟数(上一次=>{
如果(上一个===3){
addHour()
返回0
}否则{
返回上一个+1
}
})
}
常量addSecond=()=>{
设置秒(prevState=>{
如果(prevState==3){
addMinute()
返回0
}否则{
返回状态+1
}
})
}
useffect(()=>{
常量计时器=设置间隔(addSecond,600)
return()=>clearInterval(计时器)
}, [])
返回(
时间
{hours<10?0:“}{hours}
:
{minutes<10?0:“}{minutes}
:
{seconds<10?0:“}{seconds}
{seconds.toString()}
)
}
有几个问题
首先,您需要使用prev
几分钟,所以
const addMinute = () => {
setMinutes(prev => {
if (prev === 3) {
addHour()
return 0
} else {
return prev + 1
}
})
}
然后,您需要从索引中删除包装器组件,这实际上是导致双增长的原因,作为严格模式的一部分
这是通过有意地双重调用以下函数来实现的:
类组件构造函数
,呈现
,以及应组件更新
方法类组件静态
getDerivedStateFromProps
method功能组件体
状态更新程序函数(设置状态的第一个参数)
传递给
useState
、usemo
或useReducer
请参阅:问题在于您正在index.js文件中使用React.StrictMode包装器 严格模式不能自动为您检测副作用,但它可以通过使副作用更具确定性来帮助您发现副作用。这是通过故意双重调用以下函数来实现的: 因此,您应该在使用strict模式还是产生副作用之间做出决定,简单的方法是删除React.StrictMode包装器。另一种方法是消除副作用,您只需执行以下操作: 将addSecond和addMinute函数更新为如下内容:
const addMinute = () => {
setMinutes((prev) => prev + 1);
};
const addSecond = () => {
setSeconds((prevState) => prevState + 1);
};
useEffect(() => {
if(seconds === 3) {
addMinute();
setSeconds(0);
};
if(minutes === 3) {
addHour();
setMinutes(0);
}
const timer = setInterval(addSecond, 600);
return () => clearInterval(timer);
}, [seconds, minutes]);
您的useEffect调用如下内容:
const addMinute = () => {
setMinutes((prev) => prev + 1);
};
const addSecond = () => {
setSeconds((prevState) => prevState + 1);
};
useEffect(() => {
if(seconds === 3) {
addMinute();
setSeconds(0);
};
if(minutes === 3) {
addHour();
setMinutes(0);
}
const timer = setInterval(addSecond, 600);
return () => clearInterval(timer);
}, [seconds, minutes]);
这里是代码的更新版本:所以我不知道严格模式和有意的双重渲染。在阅读了文档之后,我终于明白了这个目的 因此,最好的解决方案似乎是不产生useEffect的副作用,而是在效果之外处理该逻辑,但仍然每秒钟都在变化 所以,我设置了一个效果,它有一个从零开始,每秒上升一个的状态 然后,随着“时间”的每次更改,useMemo将重新计算总时间为多少小时、分钟和秒 我唯一不喜欢的是每次渲染时都会进行计算!(但实际上,这只需要几毫秒,所以性能似乎不成问题)
const[time,setTime]=useState(0)
useffect(()=>{
常量计时器=设置间隔(()=>{
设定时间(p=>p+1)
}, 999);
return()=>clearTimeout(计时器);
},[userState]);
const timeJSON=useMemo(()=>{
常数小时=数学楼层(时间/3600)
常数分钟=数学楼层((时间-(3600*小时))/60)
常数秒=时间-(3600*小时)-(60*分钟)
返回{
高分辨率分光计,
分钟,
秒,
}
}[时间])
返回(
{timeJSON.hrs<10?0::}{timeJSON.hrs}
:
{timeJSON.mins<10?0::}{timeJSON.mins}
:
{timeJSON.secs<10?0::}{timeJSON.secs}
)
再次感谢大家为我指出了正确的方向 我无法重现这个问题。您如何知道调用了两次
addMinute()
?请阅读此评论中链接的问题的第一个答案(我怀疑此问题是重复的):--而不是删除StrictMode提供的保护,在知道后果的情况下利用它。@Turtlean在添加一些控制台日志后,它似乎没有运行两次。然而,当addMinute运行时,不知何故,当我渲染状态时,它在返回到零之前显示为“2”。为什么OP会删除一个防御性编程步骤,例如React.stricmode
?这没有什么意义。因为它会导致双重重新渲染,并导致他们遇到的问题。是的,这是正确的。我之所以这样做,是因为我是在绝望中尝试的。我已经做了调整。然而,这不是问题的原因,因为它仍然被称为twice@m4cbeth您注意到索引文件中关于React.StrictMode
的部分了吗?这就是问题的原因。@Gabriele-是的,如果你注意到我对OP问题的评论,我理解。我的观点是,你应该在你的回答中描述为什么应该删除它。这会是一个更好的解释