diff --git a/src/components/PageTitleContext.tsx b/src/components/PageTitleContext.tsx index 53e15ab..b7ed6c6 100644 --- a/src/components/PageTitleContext.tsx +++ b/src/components/PageTitleContext.tsx @@ -1,7 +1,7 @@ import { createContext, useContext, - useEffect, + useLayoutEffect, useState, type PropsWithChildren, } from "react"; @@ -31,10 +31,16 @@ export function usePageTitle(): string | null { return useContext(PageTitleContext)?.title ?? null; } -/** Publish the current page's title; clears it again when the page unmounts. */ +/** + * Publish the current page's title; clears it again when the page unmounts. + * Uses useLayoutEffect so the title updates synchronously with the page render + * — otherwise switching language (e.g. cn -> ms) showed the previous title for + * one paint while the post-commit useEffect was still pending, which read as a + * flicker in the header. + */ export function useSetPageTitle(title: string | null): void { const setTitle = useContext(PageTitleContext)?.setTitle; - useEffect(() => { + useLayoutEffect(() => { setTitle?.(title); return () => setTitle?.(null); }, [setTitle, title]);