From 125fd2dd9f4842e7ff1994ba078b2d97d954515f Mon Sep 17 00:00:00 2001 From: cottongin Date: Mon, 24 Aug 2026 01:39:55 -0400 Subject: [PATCH] fix: add stale-request guard to useStickerWall hook Co-authored-by: Cursor --- frontend/src/hooks/useStickerWall.js | 75 ++++++++++++++++------------ 1 file changed, 44 insertions(+), 31 deletions(-) diff --git a/frontend/src/hooks/useStickerWall.js b/frontend/src/hooks/useStickerWall.js index b3bcc68..f25a34b 100644 --- a/frontend/src/hooks/useStickerWall.js +++ b/frontend/src/hooks/useStickerWall.js @@ -21,32 +21,6 @@ export function useStickerWall(sessionId) { setImageUrl(url); }, [revokeUrl]); - const fetchWall = useCallback(async (id) => { - setLoading(true); - setError(false); - try { - const res = await api.get(`/stickerwalls/${id}`, { responseType: 'blob' }); - setBlobUrl(res.data); - } catch (err) { - if (err.response?.status === 404) { - try { - const renderRes = await api.post(`/stickerwalls/${id}/render`, null, { responseType: 'blob' }); - setBlobUrl(renderRes.data); - } catch (renderErr) { - revokeUrl(); - setImageUrl(null); - setError(true); - } - } else { - revokeUrl(); - setImageUrl(null); - setError(true); - } - } finally { - setLoading(false); - } - }, [setBlobUrl, revokeUrl]); - const refresh = useCallback(async () => { if (!sessionId) return; setLoading(true); @@ -62,15 +36,54 @@ export function useStickerWall(sessionId) { }, [sessionId, setBlobUrl]); useEffect(() => { - if (sessionId) { - fetchWall(sessionId); - } else { + let stale = false; + + if (!sessionId) { revokeUrl(); setImageUrl(null); setError(false); + return revokeUrl; } - return revokeUrl; - }, [sessionId, fetchWall, revokeUrl]); + + const fetchWall = async (id) => { + setLoading(true); + setError(false); + try { + const res = await api.get(`/stickerwalls/${id}`, { responseType: 'blob' }); + if (stale) return; + setBlobUrl(res.data); + } catch (err) { + if (stale) return; + if (err.response?.status === 404) { + try { + const renderRes = await api.post(`/stickerwalls/${id}/render`, null, { responseType: 'blob' }); + if (stale) return; + setBlobUrl(renderRes.data); + } catch { + if (stale) return; + revokeUrl(); + setImageUrl(null); + setError(true); + } + } else { + revokeUrl(); + setImageUrl(null); + setError(true); + } + } finally { + if (!stale) { + setLoading(false); + } + } + }; + + fetchWall(sessionId); + + return () => { + stale = true; + revokeUrl(); + }; + }, [sessionId, setBlobUrl, revokeUrl]); return { imageUrl, loading, error, refresh }; }