diff --git a/README.md b/README.md index f9105c00..2d20675a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# 3단계 완료 +# 3단계 완료 (리뷰 반영) # 목표 diff --git a/src/hooks/useThemeProducts.ts b/src/hooks/useThemeProducts.ts index e0946156..586b965f 100644 --- a/src/hooks/useThemeProducts.ts +++ b/src/hooks/useThemeProducts.ts @@ -1,4 +1,4 @@ -import { useState, useEffect, useCallback } from 'react'; +import { useState, useEffect, useCallback, useRef } from 'react'; import { apiClient } from '@/api/apiClient'; import { GiftItem } from '@/constants/GiftItem'; @@ -18,10 +18,10 @@ export function useThemeProducts(themeId: number) { const [products, setProducts] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); - const [cursor, setCursor] = useState(0); const [hasMore, setHasMore] = useState(true); + const cursorRef = useRef(0); - const fetchProducts = useCallback(async () => { + const fetchMore = useCallback(async () => { if (!themeId || !hasMore || loading) return; setLoading(true); @@ -31,7 +31,7 @@ export function useThemeProducts(themeId: number) { const res = await apiClient.get>( `/api/themes/${themeId}/products`, { - params: { cursor, limit: PRODUCTS_LIMIT }, + params: { cursor: cursorRef.current, limit: PRODUCTS_LIMIT }, } ); @@ -42,7 +42,7 @@ export function useThemeProducts(themeId: number) { ); return [...prevProducts, ...newProducts]; }); - setCursor(res.data.data.cursor); + cursorRef.current = res.data.data.cursor; setHasMore(res.data.data.hasMoreList); } } catch (err) { @@ -50,18 +50,15 @@ export function useThemeProducts(themeId: number) { } finally { setLoading(false); } - }, [themeId, hasMore, loading, cursor]); + }, [themeId, hasMore, loading]); useEffect(() => { setProducts([]); - setCursor(0); + cursorRef.current = 0; setHasMore(true); setError(null); + fetchMore(); }, [themeId]); - useEffect(() => { - fetchProducts(); - }, [fetchProducts]); - - return { products, loading, error, fetchMore: fetchProducts, hasMore }; + return { products, loading, error, fetchMore, hasMore }; } diff --git a/src/pages/ThemeProductListPage.tsx b/src/pages/ThemeProductListPage.tsx index e5d8d5fc..728fb31b 100644 --- a/src/pages/ThemeProductListPage.tsx +++ b/src/pages/ThemeProductListPage.tsx @@ -27,6 +27,7 @@ const ThemeProductListPage: React.FC = () => { const observerRef = useRef(null); const observer = useRef(null); + useEffect(() => { if (themeError && themeError.message.includes('404')) { @@ -66,6 +67,8 @@ const ThemeProductListPage: React.FC = () => { }; }, [handleObserver]); + + if (themeLoading) { return ; } @@ -139,6 +142,10 @@ const ProductGrid = styled.div` display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 16px; + + @media (min-width: 768px) { + grid-template-columns: repeat(3, 1fr); + } `; const EmptyState = styled.div`