Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/476.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 用钩子建造一个时钟_Javascript_Reactjs - Fatal编程技术网

Javascript 用钩子建造一个时钟

Javascript 用钩子建造一个时钟,javascript,reactjs,Javascript,Reactjs,我正在制作一个计时时钟,只是一个练习(我知道有更好的方法) 我的问题是,当一分钟被添加时,“addMinute”似乎会运行两次,我一辈子都不知道如何或为什么 下面是codesandbox的演示: 下面是代码一览表: (请注意,计数器最多只能计数3次,计数速度更快;这仅用于测试目的) const Clock=(道具)=>{ 常量[秒,设置秒]=使用状态(0) const[minutes,setMinutes]=useState(0) 常数[hours,setHours]=useState(0) 常

我正在制作一个计时时钟,只是一个练习(我知道有更好的方法)

我的问题是,当一分钟被添加时,“addMinute”似乎会运行两次,我一辈子都不知道如何或为什么

下面是codesandbox的演示: 下面是代码一览表:

(请注意,计数器最多只能计数3次,计数速度更快;这仅用于测试目的)

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问题的评论,我理解。我的观点是,你应该在你的回答中描述为什么应该删除它。这会是一个更好的解释