React 19 初始化 useState 导致水合错误

问题描述 投票:0回答:1

为什么我在初始化

useState
时出现水合错误?
如果初始时间戳不会出现,则 ui 看起来像空的额外空间,因为如果不初始化它,需要几秒钟的时间才出现 timeAgo

import React, { useEffect, useState } from "react";
//date formatter
const formatDate = (date) => {
  const optionsDate = {
    day: "2-digit",
    month: "short",
    year: "numeric",
  };
  const optionsTime = {
    hour: "2-digit",
    minute: "2-digit",
    hour12: true,
  };

  const formattedDate = new Intl.DateTimeFormat("en-US", optionsDate).format(
    new Date(date)
  );
  const formattedTime = new Intl.DateTimeFormat("en-US", optionsTime).format(
    new Date(date)
  );

  return `${formattedDate} - ${formattedTime}`;
};

//calculate date to ago
const calculateTimeAgo = (date) => {
  const now = new Date();
  const past = new Date(date);
  const diffInSeconds = Math.floor((now - past) / 1000);

  if (diffInSeconds < 60) return "Now";
  if (diffInSeconds < 120) return "1 min ago";
  if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)} min ago`;
  if (diffInSeconds < 7200) return "about an hour ago";
  if (diffInSeconds < 86400)
    return `${Math.floor(diffInSeconds / 3600)} hours ago`;
  if (diffInSeconds < 172800) return "1 day ago";
  if (diffInSeconds < 604800)
    return `${Math.floor(diffInSeconds / 86400)} days ago`;
  if (diffInSeconds < 1209600) return "a week ago";
  if (diffInSeconds < 2419200)
    return `${Math.floor(diffInSeconds / 604800)} weeks ago`;
  if (diffInSeconds < 5184000) return "1 month ago";

  const diffInMonths =
    (now.getFullYear() - past.getFullYear()) * 12 +
    now.getMonth() -
    past.getMonth();
  if (diffInMonths < 12) return `${Math.floor(diffInMonths)} months ago`;
  if (diffInMonths < 24) return "a year ago";

  return `${Math.floor(diffInMonths / 12)} years ago`;
};

const TimeAgo = ({ date, className }) => {
  const [timeAgo, setTimeAgo] = useState(calculateTimeAgo(date));

  useEffect(() => {
    const updateStats = () => {
      setTimeAgo(calculateTimeAgo(date));
    };
    updateStats();
    const interval = setInterval(updateStats, 60000);
    return () => clearInterval(interval);
  }, []);

  return <span className={className}>{timeAgo}</span>;
};

export default TimeAgo;
reactjs next.js
1个回答
0
投票

客户端和服务器上的 HTML 输出必须相同;否则,React 将抛出水合错误。

在您的情况下,随着时间的推移,服务器上的日期将与客户端上的日期不同。这意味着

calculateTimeAgo
函数可能会为服务器和客户端产生不同的结果。

为了缓解这种情况,您可以

suppressHydrationWarning
添加到标签中,告诉 React 忽略水合错误。

<span className={className} suppressHydrationWarning>{timeAgo}</span>

请记住,

suppressHydrationWarning
只能在这种特定情况下使用。在大多数其他水合错误情况下,问题可能是由于代码中的逻辑问题造成的。

© www.soinside.com 2019 - 2024. All rights reserved.