Next.js
React에서 상태 이름을 loading보다 구체적으로
단순한 loading 대신 상태의 목적을 명확히 하는 이름을 쓰자.
loading은 너무 모호하다
React 컴포넌트를 쓰다 보면 로딩 상태를 다룰 일이 많다. 가장 쉬운 방법은:
const [loading, setLoading] = useState(false);
하지만 이건 문제가 있다. 어떤 작업이 로딩 중인지 알 수 없다.
// 요청이 있을 때
setLoading(true);
// 요청이 실패할 때도
setLoading(true);
// 아니면 캐시 업데이트 중?
setLoading(true);
모두 loading: true가 되니까 혼란스럽다.
구체적으로 이름 짓기
상태의 목적을 반영하자:
// Before
const [loading, setLoading] = useState(false);
// After
const [isSubmitting, setIsSubmitting] = useState(false);
const [isFetchingUsers, setIsFetchingUsers] = useState(false);
const [isValidating, setIsValidating] = useState(false);
이제 어떤 작업이 진행 중인지 명확하다.
여러 상태 함께 다루기
리덕스나 Context를 쓴다면:
const [status, setStatus] = useState({
submitForm: 'idle', // 'idle' | 'loading' | 'error' | 'success'
fetchUsers: 'idle',
uploadFile: 'idle',
});
각 작업의 상태를 명확히 추적할 수 있다.
에러도 함께 추적
const [submission, setSubmission] = useState({
status: 'idle', // 'idle' | 'loading' | 'error' | 'success'
error: null,
});
// 사용할 때
if (submission.status === 'loading') {
return <Spinner />;
}
if (submission.status === 'error') {
return <Error message={submission.error} />;
}
커스텀 훅으로 정리하기
function useAsyncOperation(fn) {
const [status, setStatus] = useState('idle');
const [error, setError] = useState(null);
const execute = async (...args) => {
setStatus('loading');
try {
await fn(...args);
setStatus('success');
} catch (e) {
setError(e.message);
setStatus('error');
}
};
return { status, error, execute };
}
// 사용
const { status, error, execute } = useAsyncOperation(submitForm);
내 경험
처음엔 loading만으로 충분하다고 생각했는데, 여러 비동기 작업이 동시에 일어나니까 혼란이 생겼다. 구체적인 이름으로 바꾼 후로는 코드 읽기가 훨씬 쉬워졌다.