From 114fc0351d8164a7e96220f8da4edda832c584ee Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 17 Jun 2026 09:34:59 +0000 Subject: [PATCH 1/2] =?UTF-8?q?fix(header):=20=E5=8F=B3=E4=B8=8A=E8=A7=92?= =?UTF-8?q?=E6=97=A5=E6=9C=9F=E5=AE=A2=E6=88=B7=E7=AB=AF=E5=AE=9E=E6=97=B6?= =?UTF-8?q?=E5=88=B7=E6=96=B0=EF=BC=8C=E9=81=BF=E5=85=8D=20SSG=20=E5=86=BB?= =?UTF-8?q?=E7=BB=93=20build=20=E6=97=B6=E5=88=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Header 右侧日期原先在 server component 用 new Date() 渲染,SSG/ISR 下会被冻结在 build 时刻,导致线上长期显示陈旧日期。改为客户端组件 LiveDate,沿用 LiveEditionLabel 的固定悉尼时区 + 每秒刷新模式, 首帧用 server 时间戳保证 hydration 一致。 --- app/components/Header.tsx | 14 +++---------- app/components/LiveDate.tsx | 40 +++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 11 deletions(-) create mode 100644 app/components/LiveDate.tsx diff --git a/app/components/Header.tsx b/app/components/Header.tsx index dc802685..843195e9 100644 --- a/app/components/Header.tsx +++ b/app/components/Header.tsx @@ -8,26 +8,18 @@ import { Github as GithubIcon } from "./icons/Github"; import { AuthNav } from "./AuthNav"; import { BrandMark } from "./BrandMark"; import { LiveEditionLabel } from "./LiveEditionLabel"; +import { LiveDate } from "./LiveDate"; export async function Header() { const t = await getTranslations("header"); - const now = new Date(); - const editionTimestampMs = now.getTime(); - const formattedDate = now.toLocaleDateString("en-US", { - month: "long", - day: "numeric", - year: "numeric", - timeZone: "Australia/Sydney", - }); + const editionTimestampMs = Date.now(); return (
-
- {formattedDate} -
+
diff --git a/app/components/LiveDate.tsx b/app/components/LiveDate.tsx new file mode 100644 index 00000000..9b0339f4 --- /dev/null +++ b/app/components/LiveDate.tsx @@ -0,0 +1,40 @@ +"use client"; + +import { useEffect, useState } from "react"; + +type LiveDateProps = { + // milliseconds since epoch + initialTimestamp: number; +}; + +// 固定时区(悉尼)保证服务端/客户端首帧一致,避免 hydration mismatch; +// 挂载后每秒刷新,避免 SSG/ISR 把 build 时刻的日期冻住。 +const TIMEZONE = "Australia/Sydney"; + +function formatDate(ms: number) { + return new Date(ms).toLocaleDateString("en-US", { + month: "long", + day: "numeric", + year: "numeric", + timeZone: TIMEZONE, + }); +} + +export function LiveDate({ initialTimestamp }: LiveDateProps) { + const [formattedDate, setFormattedDate] = useState(() => + formatDate(initialTimestamp), + ); + + useEffect(() => { + const update = () => setFormattedDate(formatDate(Date.now())); + update(); + const intervalId = setInterval(update, 1000); + return () => clearInterval(intervalId); + }, []); + + return ( +
+ {formattedDate} +
+ ); +} From 8969f1fbb5ff44b1ae7acca546750573c18f2937 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 17 Jun 2026 09:37:33 +0000 Subject: [PATCH 2/2] =?UTF-8?q?fix(header):=20=E7=94=A8=20new=20Date().get?= =?UTF-8?q?Time()=20=E9=81=BF=E5=85=8D=20react-hooks/purity=20=E6=8A=A5?= =?UTF-8?q?=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Date.now() 被 react-hooks/purity 规则判为 render 期不纯调用, 改用与原实现一致的 new Date().getTime()。 --- app/components/Header.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/Header.tsx b/app/components/Header.tsx index 843195e9..fdcf78ba 100644 --- a/app/components/Header.tsx +++ b/app/components/Header.tsx @@ -12,7 +12,7 @@ import { LiveDate } from "./LiveDate"; export async function Header() { const t = await getTranslations("header"); - const editionTimestampMs = Date.now(); + const editionTimestampMs = new Date().getTime(); return (