diff --git a/src/pages/travel/useTravelData.js b/src/pages/travel/useTravelData.js index 9173425..f885a83 100644 --- a/src/pages/travel/useTravelData.js +++ b/src/pages/travel/useTravelData.js @@ -73,6 +73,7 @@ const useTravelData = () => { const currentAlbumRef = useRef(null); // { regionId, albumName } const cacheRef = useRef(new Map()); // photo data cache key: `${regionId}::${albumName}` const albumCacheRef = useRef(new Map()); // album metadata cache key: regionId + const loadAbortRef = useRef(null); // AbortController for loadAlbumPhotos /* ── Load GeoJSON regions once ──────────── */ useEffect(() => { @@ -195,7 +196,10 @@ const useTravelData = () => { setHasNext(false); pageRef.current = 1; + // Abort any in-flight loadAlbumPhotos request + if (loadAbortRef.current) loadAbortRef.current.abort(); const controller = new AbortController(); + loadAbortRef.current = controller; try { let url = `/api/travel/photos?region=${encodeURIComponent(regionId)}&page=1&size=${PAGE_SIZE}`; if (albumName) url += `&album=${encodeURIComponent(albumName)}`; @@ -241,11 +245,12 @@ const useTravelData = () => { setLoadingMore(true); setError(''); + const moreController = new AbortController(); try { let url = `/api/travel/photos?region=${encodeURIComponent(activeRegion)}&page=${pageRef.current}&size=${PAGE_SIZE}`; if (activeAlbum) url += `&album=${encodeURIComponent(activeAlbum)}`; - const res = await fetch(url); + const res = await fetch(url, { signal: moreController.signal }); if (!res.ok) throw new Error(`사진 로딩 실패 (${res.status})`); const json = await res.json(); const { normalized, hasNext: hn, summary } = parsePhotoResponse(json); @@ -289,26 +294,32 @@ const useTravelData = () => { let url = `/api/travel/photos?region=${encodeURIComponent(activeRegion)}&page=1&size=${PAGE_SIZE}`; if (activeAlbum) url += `&album=${encodeURIComponent(activeAlbum)}`; - const res = await fetch(url); - if (!res.ok) throw new Error(`사진 로딩 실패 (${res.status})`); - const json = await res.json(); - const { normalized, hasNext: hn, summary } = parsePhotoResponse(json); + const reloadController = new AbortController(); + try { + const res = await fetch(url, { signal: reloadController.signal }); + if (!res.ok) throw new Error(`사진 로딩 실패 (${res.status})`); + const json = await res.json(); + const { normalized, hasNext: hn, summary } = parsePhotoResponse(json); - const filtered = activeAlbum - ? normalized.filter((p) => !p.album || p.album === activeAlbum) - : normalized; + const filtered = activeAlbum + ? normalized.filter((p) => !p.album || p.album === activeAlbum) + : normalized; - pageRef.current = 2; - setPhotos(filtered); - setHasNext(hn); - cacheRef.current.set(cacheKey, { - timestamp: Date.now(), - items: filtered, - page: 2, - hasNext: hn, - summary, - }); - if (summary) setPhotoSummary(summary); + pageRef.current = 2; + setPhotos(filtered); + setHasNext(hn); + cacheRef.current.set(cacheKey, { + timestamp: Date.now(), + items: filtered, + page: 2, + hasNext: hn, + summary, + }); + if (summary) setPhotoSummary(summary); + } catch (err) { + if (err?.name === 'AbortError') return; + setError(err?.message ?? String(err)); + } }, []); /* ── getFilteredAlbums — filter by region ─ */