Search
🚀

선언적 데이터 페칭 미니과제 - Before

다음과 같은 요구사항이 있습니다.
사용자 목록과 카테고리 목록을 동시에 가져오기
로딩 중일 때 스켈레톤 UI 표시
에러 발생 시 재시도 버튼 표시
5분마다 자동 새로고침
아래 코드를 유지보수성을 고려하여 개선해주세요. 풀이 과정은 Think Aloud 하여 녹화로 남겨주세요.
function Dashboard() { const [users, setUsers] = useState([]); const [categories, setCategories] = useState([]); const [loadingUsers, setLoadingUsers] = useState(false); const [loadingCategories, setLoadingCategories] = useState(false); const [errorUsers, setErrorUsers] = useState(null); const [errorCategories, setErrorCategories] = useState(null); // 사용자 fetch 함수 const fetchUsers = async () => { setLoadingUsers(true); setErrorUsers(null); try { const response = await fetch('/api/users'); if (!response.ok) throw new Error('사용자 로드 실패'); const data = await response.json(); setUsers(data); } catch (error) { setErrorUsers(error.message); } finally { setLoadingUsers(false); } }; // 카테고리 fetch 함수 const fetchCategories = async () => { setLoadingCategories(true); setErrorCategories(null); try { const response = await fetch('/api/categories'); if (!response.ok) throw new Error('카테고리 로드 실패'); const data = await response.json(); setCategories(data); } catch (error) { setErrorCategories(error.message); } finally { setLoadingCategories(false); } }; // 초기 로드 useEffect(() => { fetchUsers(); }, []); useEffect(() => { fetchCategories(); }, []); // 5분마다 자동 새로고침 - users useEffect(() => { const interval = setInterval(() => { fetchUsers(); }, 5 * 60 * 1000); return () => clearInterval(interval); }, []); // 5분마다 자동 새로고침 - categories useEffect(() => { const interval = setInterval(() => { fetchCategories(); }, 5 * 60 * 1000); return () => clearInterval(interval); }, []); // 재시도 로직 const retryUsers = () => { fetchUsers(); }; const retryCategories = () => { fetchCategories(); }; return ( <div className="p-6"> <div className="grid grid-cols-2 gap-4"> {/* Users Section */} <div className="border rounded p-4"> <h3 className="font-semibold mb-2">사용자 목록</h3> {loadingUsers && <Spinner />} {errorUsers && <ErrorSection onClick={retryUsers} />} {!loadingUsers && !errorUsers && ( <ul> {users.map((user, idx) => ( <li key={idx}>{user.name}</li> ))} </ul> )} </div> {/* Categories Section */} <div className="border rounded p-4"> <h3 className="font-semibold mb-2">카테고리 목록</h3> {loadingCategories && <Spinner />} {errorCategories && <ErrorSection onClick={retryCategories} />} {!loadingCategories && !errorCategories && ( <ul> {categories.map((category, idx) => ( <li key={idx}>{category.name}</li> ))} </ul> )} </div> </div> </div> ); } function Spinner({ onClick }) { return <div className="animate-pulse bg-gray-200 h-20 rounded" /> } function ErrorSection() { return ( <div className="text-red-500"> <button onClick={onClick} className="bg-red-500 text-white px-3 py-1 rounded mt-2" > 재시도 </button> </div> ) }
TypeScript
복사