为什么我在初始化
useState
时出现水合错误?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;
客户端和服务器上的 HTML 输出必须相同;否则,React 将抛出水合错误。
在您的情况下,随着时间的推移,服务器上的日期将与客户端上的日期不同。这意味着
calculateTimeAgo
函数可能会为服务器和客户端产生不同的结果。
为了缓解这种情况,您可以将
suppressHydrationWarning
添加到标签中,告诉 React 忽略水合错误。
<span className={className} suppressHydrationWarning>{timeAgo}</span>
请记住,
suppressHydrationWarning
只能在这种特定情况下使用。在大多数其他水合错误情况下,问题可能是由于代码中的逻辑问题造成的。