fix(travel): useTravelData AbortController 및 에러 핸들링 보완
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -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 ─ */
|
||||
|
||||
Reference in New Issue
Block a user