From 9534e692d639872a0d407191cd58d682b67141b5 Mon Sep 17 00:00:00 2001 From: ronload <91997734+ronload@users.noreply.github.com> Date: Wed, 15 Apr 2026 16:35:17 +0800 Subject: [PATCH] fix(map): resolve loading stuck caused by module-level promise ref The module-level mapModulePromise held a single promise reference that the useEffect .then() consumed. Two issues caused the map to stay in loading state intermittently: 1. On chunk-load failure the rejected (but truthy) promise prevented the nullish-coalescing fallback from firing, so TaiwanMap stayed null with no retry path. 2. Under React 19 Strict Mode the cancelled-flag lifecycle could race with the shared promise resolution timing. Replace the stored promise with a fire-and-forget preload -- the bundler caches the module anyway, so a second import() in useEffect resolves instantly. Also add a one-shot retry on transient chunk-load failures. --- src/components/address-page.tsx | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/src/components/address-page.tsx b/src/components/address-page.tsx index f471842..1a270a6 100644 --- a/src/components/address-page.tsx +++ b/src/components/address-page.tsx @@ -8,16 +8,15 @@ import { AddressForm } from "@/components/address-form"; // Module-level: start downloading the map chunk during hydration (before any // useEffect fires). Only on desktop to avoid wasting mobile bandwidth. +// The bundler caches the module, so subsequent import() calls in useEffect +// resolve instantly without an extra network request. // Also prime the HTTP cache for counties data in parallel. const isDesktopAtLoad = typeof window !== "undefined" && window.matchMedia("(min-width: 1024px)").matches; -const mapModulePromise = isDesktopAtLoad - ? import("@/components/taiwan-map") - : null; - if (isDesktopAtLoad) { + void import("@/components/taiwan-map"); void fetch("/data/map/counties-10t.json"); } @@ -40,15 +39,23 @@ export function AddressPage({ cities }: AddressPageProps) { let cancelled = false; - // If the module-level preload started, reuse that promise; - // otherwise start a fresh download (e.g. viewport was resized to desktop). - const promise = mapModulePromise ?? import("@/components/taiwan-map"); - - void promise.then((mod) => { - if (!cancelled) { - setTaiwanMap(() => mod.TaiwanMap); - } - }); + // The bundler caches dynamic imports, so this resolves instantly if the + // module-level preload already completed. No module-level promise ref + // needed -- avoids Strict-Mode / HMR race conditions and adds retry on + // transient chunk-load failures. + import("@/components/taiwan-map").then( + (mod) => { + if (!cancelled) setTaiwanMap(() => mod.TaiwanMap); + }, + () => { + // Retry once on transient chunk-load failure + if (!cancelled) { + void import("@/components/taiwan-map").then((mod) => { + if (!cancelled) setTaiwanMap(() => mod.TaiwanMap); + }); + } + }, + ); return () => { cancelled = true;