
프론트엔드 개발에서 데이터 로딩 상태를 관리하는 것은 매우 중요한 부분입니다. 이 글에서는 전통적인 useEffect를 이용한 방식과 React의 새로운 기능인 Suspense를 활용한 방식을 비교해보겠습니다.
function UserProfile() {
const [data, setData] = useState(null);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
setIsLoading(true);
const response = await fetch('/api/user');
const result = await response.json();
setData(result);
} catch (err) {
setError(err);
} finally {
setIsLoading(false);
}
};
fetchData();
}, []);
if (isLoading) return <LoadingSpinner />;
if (error) return <ErrorMessage error={error} />;
return <UserInfo data={data} />;
}
// 데이터 페칭을 위한 리소스 생성
function createResource(asyncFn) {
let status = 'pending';
let result;
let suspender = asyncFn().then(
(data) => {
status = 'success';
result = data;
},
(error) => {
status = 'error';
result = error;
}
);
return {
read() {
if (status === 'pending') {
throw suspender;
} else if (status === 'error') {
throw result;
} else if (status === 'success') {
return result;
}
}
};
}
// 컴포넌트에서 사용
function UserProfile() {
const resource = useMemo(() => createResource(
() => fetch('/api/user').then(res => res.json())
), []);
return (
<Suspense fallback={<LoadingSpinner />}>
<UserInfo data={resource.read()} />
</Suspense>
);
}
if (isLoading) return <LoadingSpinner />;
return <ActualContent />;<Suspense fallback={<LoadingSpinner />}>
<ActualContent />
</Suspense>useEffect 선택 시기
Suspense 선택 시기
각 방식은 장단점이 있으므로, 프로젝트의 요구사항과 상황에 맞게 선택하는 것이 중요합니다. Suspense는 React의 미래를 대표하는 기능이지만, 아직 실험적 기능이므로 프로덕션 환경에서 사용 시 신중한 검토가 필요합니다.