Description
DeadlineCountdown still causes a React hydration mismatch error in the console. The current fix (PR #153) uses typeof window === "undefined" in useState initializer, but this doesn't prevent the mismatch — server renders --:--:-- while client initializes to the calculated value (e.g., 71) during hydration.
Console error
Uncaught Error: Hydration failed because the server rendered text didn't match the client.
+ 71
- --:--:--
Root cause
useState(() => typeof window === "undefined" ? null : calcRemaining(...)) — on the client during hydration, window exists so it computes the countdown value immediately, but the server rendered --:--:-- (null state). These don't match.
File
src/components/DeadlineCountdown.tsx
Fix
Always initialize state as null (no conditional). Only set the calculated value inside useEffect after mount:
const [remaining, setRemaining] = useState<number | null>(null);
useEffect(() => {
setRemaining(calcRemaining(lastPlotTime));
const interval = setInterval(() => {
setRemaining(calcRemaining(lastPlotTime));
}, 1000);
return () => clearInterval(interval);
}, [lastPlotTime]);
This ensures server and client both render --:--:-- during hydration, then the countdown starts after mount.
🤖 Generated with Claude Code
Description
DeadlineCountdownstill causes a React hydration mismatch error in the console. The current fix (PR #153) usestypeof window === "undefined"inuseStateinitializer, but this doesn't prevent the mismatch — server renders--:--:--while client initializes to the calculated value (e.g.,71) during hydration.Console error
Root cause
useState(() => typeof window === "undefined" ? null : calcRemaining(...))— on the client during hydration,windowexists so it computes the countdown value immediately, but the server rendered--:--:--(null state). These don't match.File
src/components/DeadlineCountdown.tsxFix
Always initialize state as
null(no conditional). Only set the calculated value insideuseEffectafter mount:This ensures server and client both render
--:--:--during hydration, then the countdown starts after mount.🤖 Generated with Claude Code