fix: fix hydration mismatch for DrawIO theme loading (#131)

- Load DrawIO theme from localStorage after mount with useEffect
- Add loading spinner while theme loads
- Prevents SSR/client hydration mismatch (server has no localStorage)

Co-authored-by: dayuan.jiang <jiangdy@amazon.co.jp>
This commit is contained in:
Dayuan Jiang
2025-12-07 00:45:19 +09:00
committed by GitHub
parent 4be64317b3
commit 05d58025c4

View File

@@ -15,20 +15,26 @@ export default function Home() {
const { drawioRef, handleDiagramExport } = useDiagram() const { drawioRef, handleDiagramExport } = useDiagram()
const [isMobile, setIsMobile] = useState(false) const [isMobile, setIsMobile] = useState(false)
const [isChatVisible, setIsChatVisible] = useState(true) const [isChatVisible, setIsChatVisible] = useState(true)
const [drawioUi, setDrawioUi] = useState<"min" | "sketch">(() => { const [drawioUi, setDrawioUi] = useState<"min" | "sketch">("min")
if (typeof window !== "undefined") { const [isThemeLoaded, setIsThemeLoaded] = useState(false)
const saved = localStorage.getItem("drawio-theme")
if (saved === "min" || saved === "sketch") return saved // Load theme from localStorage after mount to avoid hydration mismatch
useEffect(() => {
const saved = localStorage.getItem("drawio-theme")
if (saved === "min" || saved === "sketch") {
setDrawioUi(saved)
} }
return "min" setIsThemeLoaded(true)
}) }, [])
const [closeProtection, setCloseProtection] = useState(() => { const [closeProtection, setCloseProtection] = useState(true)
if (typeof window !== "undefined") {
const saved = localStorage.getItem(STORAGE_CLOSE_PROTECTION_KEY) // Load close protection setting from localStorage after mount
return saved !== "false" // Default to true useEffect(() => {
const saved = localStorage.getItem(STORAGE_CLOSE_PROTECTION_KEY)
if (saved === "false") {
setCloseProtection(false)
} }
return true }, [])
})
const chatPanelRef = useRef<ImperativePanelHandle>(null) const chatPanelRef = useRef<ImperativePanelHandle>(null)
useEffect(() => { useEffect(() => {
@@ -96,18 +102,24 @@ export default function Home() {
}`} }`}
> >
<div className="h-full rounded-xl overflow-hidden shadow-soft-lg border border-border/30 bg-white"> <div className="h-full rounded-xl overflow-hidden shadow-soft-lg border border-border/30 bg-white">
<DrawIoEmbed {isThemeLoaded ? (
key={drawioUi} <DrawIoEmbed
ref={drawioRef} key={drawioUi}
onExport={handleDiagramExport} ref={drawioRef}
urlParameters={{ onExport={handleDiagramExport}
ui: drawioUi, urlParameters={{
spin: true, ui: drawioUi,
libraries: false, spin: true,
saveAndExit: false, libraries: false,
noExitBtn: true, saveAndExit: false,
}} noExitBtn: true,
/> }}
/>
) : (
<div className="h-full w-full flex items-center justify-center">
<div className="animate-spin h-8 w-8 border-4 border-primary border-t-transparent rounded-full" />
</div>
)}
</div> </div>
</div> </div>
</ResizablePanel> </ResizablePanel>