fix(autosave): start late-installed impl for already-mounted hooks
The overlay's auto-save implementation arrives via a dynamic import that races the first React commit. A hook whose mount effect ran before the overlay chunk evaluated saw installedImpl === null and stayed idle for the whole life of the tab: no debounced saves, no beforeunload flush, with no visible symptom. Any tab that hard-loaded straight into the editor and never remounted it silently lost every edit made after the project was bound. installAutoSaveImpl now wakes hooks that mounted before it ran, so the implementation starts as soon as it exists. Swapping a live impl at runtime remains unsupported.
This commit is contained in:
parent
a79d8fd563
commit
96c1b3323c
|
|
@ -30,18 +30,36 @@ const IDLE: AutoSaveState = { status: 'idle', lastSavedAt: null, errorMessage: n
|
|||
|
||||
let installedImpl: AutoSaveImpl | null = null;
|
||||
|
||||
/** Hooks that mounted before an impl was installed, waiting to start it. */
|
||||
const installWaiters = new Set<() => void>();
|
||||
|
||||
export function installAutoSaveImpl(impl: AutoSaveImpl | null): void {
|
||||
installedImpl = impl;
|
||||
// Overlays load through a dynamic import that races the first React
|
||||
// commit: a hook whose mount effect ran before the overlay chunk
|
||||
// evaluated used to see `installedImpl === null` and stay idle for the
|
||||
// whole life of the tab — no auto-save, no unload flush. Start those
|
||||
// already-mounted hooks now that the impl exists.
|
||||
if (impl) installWaiters.forEach((start) => start());
|
||||
}
|
||||
|
||||
export function useAutoSaveProject(): AutoSaveState {
|
||||
const [state, setState] = useState<AutoSaveState>(IDLE);
|
||||
|
||||
useEffect(() => {
|
||||
if (!installedImpl) return;
|
||||
return installedImpl(setState);
|
||||
// Mount-only — impl is installed at module load, swapping at runtime is unsupported.
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
let cleanup: (() => void) | null = null;
|
||||
const start = () => {
|
||||
if (installedImpl && !cleanup) cleanup = installedImpl(setState);
|
||||
};
|
||||
start();
|
||||
// Late-install support only — swapping a live impl at runtime is still
|
||||
// unsupported (the first installed impl keeps running until unmount).
|
||||
installWaiters.add(start);
|
||||
return () => {
|
||||
installWaiters.delete(start);
|
||||
cleanup?.();
|
||||
cleanup = null;
|
||||
};
|
||||
}, []);
|
||||
|
||||
return state;
|
||||
|
|
|
|||
Loading…
Reference in New Issue