fix(offline): avoid SSR/CSR hydration mismatch on navigator.onLine

Replace useState+lazy-initializer with useSyncExternalStore so the server
snapshot (() => false) and client snapshot (() => navigator.onLine) are
declared separately. React hydrates with the server value and switches to
the real online status client-side without a mismatch.
This commit is contained in:
diegosouzapw
2026-05-19 19:58:21 -03:00
parent 29c5a03efe
commit ef800eee40

View File

@@ -1,25 +1,24 @@
"use client";
import { useEffect, useState } from "react";
import { useSyncExternalStore } from "react";
import Link from "next/link";
function subscribeToOnline(callback: () => void) {
window.addEventListener("online", callback);
window.addEventListener("offline", callback);
return () => {
window.removeEventListener("online", callback);
window.removeEventListener("offline", callback);
};
}
export default function OfflinePage() {
const [isOnline, setIsOnline] = useState<boolean>(() =>
typeof navigator !== "undefined" ? navigator.onLine : true
const isOnline = useSyncExternalStore(
subscribeToOnline,
() => navigator.onLine,
() => false
);
useEffect(() => {
const onOnline = () => setIsOnline(true);
const onOffline = () => setIsOnline(false);
window.addEventListener("online", onOnline);
window.addEventListener("offline", onOffline);
return () => {
window.removeEventListener("online", onOnline);
window.removeEventListener("offline", onOffline);
};
}, []);
return (
<main className="min-h-screen bg-bg text-text-main flex items-center justify-center p-6">
<section className="w-full max-w-xl rounded-2xl border border-border bg-surface p-8 shadow-soft text-center">