英文:
The first timer in a react component list is getting value NaN
问题
我有一个React网站,其中有两个切换按钮,用于不同类型的卡片 - 其中一个是实时市场(这种类型有一个计时器组件)。
以下是计时器组件的代码-
import { useState, useEffect } from 'react';
export default function Timer({ id, endTime }) {
const [remainingTime, setRemainingTime] = useState(getRemainingTime());
useEffect(() => {
const interval = setInterval(() => {
setRemainingTime(getRemainingTime());
}, 1000);
return () => clearInterval(interval);
}, []);
function getRemainingTime() {
const now = new Date();
const end = new Date(endTime);
const diff = end.getTime() - now.getTime();
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
const hours = Math.floor((diff / (1000 * 60 * 60)) % 24);
const minutes = Math.floor((diff / (1000 * 60)) % 60);
const seconds = Math.floor((diff / 1000) % 60);
return { days, hours, minutes, seconds };
}
console.log('endtime-', id, endTime)
console.log('remtime-', id, remainingTime.seconds)
return (
<div className={remainingTime.seconds < 0 ? 'timer-ended' : 'timer'}>
{remainingTime.seconds < 0 ? (
"拍卖结束"
) : (
<>
拍卖剩余时间:{remainingTime.days} 天 {remainingTime.hours}:
{remainingTime.minutes}:{remainingTime.seconds}
</>
)}
</div>
);
}
还有两个控制台语句。这些值每秒都会打印出来。以下是具有NaN的计时器所打印的内容-
endtime- 4 2023-06-09T20:30:00.000Z
remtime- 4 NaN
英文:
I have a React website where I have 2 toggles for different kinds of cards - one of them is Live markets (this type has a timer component).
Here is the problem- When I switch to classifieds and I switch back to live markets -
Auction timer for the first card becomes NaN. Note: this only happens to the first card, the other timers are fine.
I have a CardsLayout component, which send a request to the server for data when the above toggle is changed. And if it is in Live Markets tab, then the CardsLayout component maps each object to an AuctionCard component which has a Timer component inside it.
Here is the code for the Timer component-
import { useState, useEffect } from 'react';
export default function Timer({ id, endTime}) {
const [remainingTime, setRemainingTime] = useState(getRemainingTime());
useEffect(() => {
const interval = setInterval(() => {
setRemainingTime(getRemainingTime());
}, 1000);
return () => clearInterval(interval);
}, []);
function getRemainingTime() {
const now = new Date();
const end = new Date(endTime);
const diff = end.getTime() - now.getTime();
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
const hours = Math.floor((diff / (1000 * 60 * 60)) % 24);
const minutes = Math.floor((diff / (1000 * 60)) % 60);
const seconds = Math.floor((diff / 1000) % 60);
return { days, hours, minutes, seconds };
}
console.log('endtime-',id,endTime)
console.log('remtime-',id,remainingTime.seconds)
return (
<div className={remainingTime.seconds < 0 ? 'timer-ended' : 'timer'}>
{remainingTime.seconds < 0 ? (
"Auction over"
) : (
<>
Auction time remaining: {remainingTime.days} Days {remainingTime.hours}:
{remainingTime.minutes}:{remainingTime.seconds}
</>
)}
</div>
);
}
I also have 2 console statements. The values are getting printed every second. Here is whats getting printed for the Timer with NaN-
endtime- 4 2023-06-09T20:30:00.000Z
remtime- 4 NaN
答案1
得分: 2
自从您将id
和endTime
添加为useEffect
的依赖项(如在OP的评论中提到的)之后,似乎问题在于首次渲染第一个Time
时,没有或者有一个错误的endTime
,所以最终显示为NaN
。
我假设在从某个地方获取数据后,随后的渲染会提供有效的endTime
值。
最初更改该属性的值不会影响进行中间隔的功能,因为getRemainingTime
将引用endTime
的初始值。
有几种解决此问题的方法。
- 在有有效数据提供给
Timer
之前,不要渲染Timer
组件。这需要在使用Timer
的组件中处理,而不是在内部处理。 - 在使用
Timer
组件时为其提供一个key
(<Timer key={/*您用于id的任何内容在这里也很可能有效*/} id={..} endTime={..} />
),这个key
应该是唯一的,并且在从远程位置获取数据后会更改。 - 对于3,更正确的方法不是将
id
和endTime
添加到useEffect
中,而是使用useCallback
,将endTime
用于getRemainingTime
,然后将其用作useEffect
的依赖项。
const getRemainingTime = useCallback(function() {
const now = new Date();
const end = new Date(endTime);
const diff = end.getTime() - now.getTime();
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
const hours = Math.floor((diff / (1000 * 60 * 60)) % 24);
const minutes = Math.floor((diff / (1000 * 60)) % 60);
const seconds = Math.floor((diff / 1000) % 60);
return { days, hours, minutes, seconds };
}, [endTime]);
useEffect(() => {
const interval = setInterval(() => {
setRemainingTime(getRemainingTime());
}, 1000);
return () => clearInterval(interval);
}, [getRemainingTime]);
英文:
Since it works after you add id
and endTime
as dependencies to the useEffect
(as mentioned in the comments of the OP), it seems that the issue is that the first render you do of the first Time
is done without/or with a wrong endTime
so it end up displaying NaN
.
Subsequent renders, I assume after fetching the data from somewhere, provide a valid endTime
value for that property.
Initially the change in that prop would not alter the functionality of the ongoing interval, since the getRemainingTime
would refer to the initial value of endTime
.
There are a few solutions to this problem.
- Do not render the
Timer
component until after you have valid data to provide to it. This need to be handled at the component using theTimer
and not inside it. - Provide a
key
for theTimer
component when using it (<Timer key={/*what ever you use for id will most likely work here too*/} id={..} endTime={..} />
that is unique and would change once you get the data from the remote location. - Use correct dependencies for the
useEffect
.
For 3. the more correct approach is not to add id
and endTime
to the useEffect
but to use useCallback
, with endTime
for the getRemainingTime
and then use that as dependency for the useEffect
.
<!-- language: lang-js -->
const getRemainingTime = useCallback(function() {
const now = new Date();
const end = new Date(endTime);
const diff = end.getTime() - now.getTime();
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
const hours = Math.floor((diff / (1000 * 60 * 60)) % 24);
const minutes = Math.floor((diff / (1000 * 60)) % 60);
const seconds = Math.floor((diff / 1000) % 60);
return { days, hours, minutes, seconds };
}, [endTime]);
useEffect(() => {
const interval = setInterval(() => {
setRemainingTime(getRemainingTime());
}, 1000);
return () => clearInterval(interval);
}, [getRemainingTime]);
答案2
得分: 0
问题出在数据处理上。你代码中的潜在问题在这里。在这一行之前,你需要控制台输出差异(diff)。在特定情况下,diff 可能为 0。当 diff 为 0 时,下面的语句会给出 NAN。
const seconds = Math.floor((diff / 1000) % 60);
你可以尝试的修复方法
const seconds = diff ? Math.floor((diff / 1000) % 60) : 0 ;
英文:
Okay so the problem is handling of the data. The potential problem in your code is here. you need to console the diff before this line. diff can be 0 in a particular case. When diff will be 0 the statement written below will give you NAN
const seconds = Math.floor((diff / 1000) % 60);
Fix you can try
const seconds = diff ? Math.floor((diff / 1000) % 60) : 0 ;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论