在React组件列表中,第一个定时器的值为NaN。

huangapple go评论172阅读模式
英文:

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).

在React组件列表中,第一个定时器的值为NaN。

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.

在React组件列表中,第一个定时器的值为NaN。

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 &#39;react&#39;;
export default function Timer({ id, endTime}) {
const [remainingTime, setRemainingTime] = useState(getRemainingTime());
useEffect(() =&gt; {
const interval = setInterval(() =&gt; {
setRemainingTime(getRemainingTime());
}, 1000);
return () =&gt; 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(&#39;endtime-&#39;,id,endTime)
console.log(&#39;remtime-&#39;,id,remainingTime.seconds)
return (
&lt;div className={remainingTime.seconds &lt; 0 ? &#39;timer-ended&#39; : &#39;timer&#39;}&gt;
{remainingTime.seconds &lt; 0 ? (
&quot;Auction over&quot;
) : (
&lt;&gt;
Auction time remaining: {remainingTime.days} Days {remainingTime.hours}:
{remainingTime.minutes}:{remainingTime.seconds}
&lt;/&gt;
)}
&lt;/div&gt;
);
}

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

自从您将idendTime添加为useEffect的依赖项(如在OP的评论中提到的)之后,似乎问题在于首次渲染第一个Time时,没有或者有一个错误的endTime,所以最终显示为NaN

我假设在从某个地方获取数据后,随后的渲染会提供有效的endTime值。

最初更改该属性的值不会影响进行中间隔的功能,因为getRemainingTime将引用endTime的初始值。

有几种解决此问题的方法。

  1. 在有有效数据提供给Timer之前,不要渲染Timer组件。这需要在使用Timer的组件中处理,而不是在内部处理。
  2. 在使用Timer组件时为其提供一个key<Timer key={/*您用于id的任何内容在这里也很可能有效*/} id={..} endTime={..} />),这个key应该是唯一的,并且在从远程位置获取数据后会更改。
  3. 对于3,更正确的方法不是将idendTime添加到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.

  1. 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 the Timer and not inside it.
  2. Provide a key for the Timer component when using it (&lt;Timer key={/*what ever you use for id will most likely work here too*/} id={..} endTime={..} /&gt; that is unique and would change once you get the data from the remote location.
  3. 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(() =&gt; {
const interval = setInterval(() =&gt; {
setRemainingTime(getRemainingTime());
}, 1000);
return () =&gt; 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 ;

huangapple
  • 本文由 发表于 2023年6月2日 02:47:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/76384846.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定