다음과 같은 요구사항이 있습니다.
•
사용자 목록과 카테고리 목록을 동시에 가져오기
•
로딩 중일 때 스켈레톤 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
복사
