fix: MEDIUM issues #23-#30 — stale deps, export modal, cache race, StrictMode dedup, SeatingService ref, SVG import persist, group-as-block multi-select, session expiry
This commit is contained in:
@@ -349,12 +349,20 @@ export async function createBlockTyped(token: string, drawingId: string, block:
|
||||
return dbBlockToFrontend(raw);
|
||||
}
|
||||
|
||||
const projectLoadCache = new Map<string, Promise<ProjectData>>();
|
||||
const projectLoadCache = new Map<string, { promise: Promise<ProjectData>; requestId: number }>();
|
||||
const projectLoadRequestCounter = new Map<string, number>();
|
||||
|
||||
export async function loadProjectDataTyped(token: string, projectId: string): Promise<ProjectData> {
|
||||
// Dedup concurrent calls (React StrictMode double-render)
|
||||
// Generate a new request ID to track the latest request for this project
|
||||
const currentRequestId = (projectLoadRequestCounter.get(projectId) ?? 0) + 1;
|
||||
projectLoadRequestCounter.set(projectId, currentRequestId);
|
||||
|
||||
// Dedup concurrent calls (React StrictMode double-render): if there is an in-flight
|
||||
// request with the same ID, reuse it. Otherwise start a fresh one.
|
||||
const existing = projectLoadCache.get(projectId);
|
||||
if (existing) return existing;
|
||||
if (existing && existing.requestId === currentRequestId - 1) {
|
||||
return existing.promise;
|
||||
}
|
||||
|
||||
const promise = (async () => {
|
||||
const drawings = await getDrawings(token, projectId);
|
||||
@@ -373,6 +381,13 @@ export async function loadProjectDataTyped(token: string, projectId: string): Pr
|
||||
getBlocks(token, drawing.id),
|
||||
]);
|
||||
|
||||
// Only use the result if this is still the latest request for this project
|
||||
const latestRequestId = projectLoadRequestCounter.get(projectId);
|
||||
if (latestRequestId !== currentRequestId) {
|
||||
// A newer request superseded this one — reject to prevent stale data
|
||||
throw new Error('Superseded by a newer load request');
|
||||
}
|
||||
|
||||
return {
|
||||
project,
|
||||
drawing,
|
||||
@@ -382,8 +397,14 @@ export async function loadProjectDataTyped(token: string, projectId: string): Pr
|
||||
};
|
||||
})();
|
||||
|
||||
projectLoadCache.set(projectId, promise);
|
||||
promise.finally(() => projectLoadCache.delete(projectId));
|
||||
projectLoadCache.set(projectId, { promise, requestId: currentRequestId });
|
||||
promise.finally(() => {
|
||||
// Only clear cache if this is still the latest request
|
||||
const cached = projectLoadCache.get(projectId);
|
||||
if (cached && cached.requestId === currentRequestId) {
|
||||
projectLoadCache.delete(projectId);
|
||||
}
|
||||
});
|
||||
return promise;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user