프로젝트를 하면서 비동기로 데이터를 받아오는 작업을 많이 했는데, 그 때 활용하면 좋을 로딩 관련
그러니까, 로그인 관련한 로딩
패치 받는 것에 관련한 로딩
우선 영화 페이지에서는 크게 이렇게 있을 것 같은데
(이 두가지는 분야가 아예 다르기 때문에, 전역 상태도 따로 관리하면 좋을 것 같다.)
비슷한 부류끼리 공통 로딩 컴포넌트 만들거나,
그 때 그 때 만들어주면 좋을 것 같다.
챗 지피티가 설명해준 그 외에 추가로 로딩 로직 넣으면 좋을 곳 ↓
로그인, 데이터 패치 외에 로딩 스피너나 로딩 상태 표시를 적용하면 좋은 곳 몇 가지 추천해드릴게요.
1. 로그인 관련 로딩
- 로그인 요청 중일 때: 서버에 로그인 요청 보내는 동안 버튼 비활성화 + 로딩 표시
- 로그인 후 사용자 정보 받아오는 중: 토큰 검증, 프로필 데이터 로딩 시 로딩 UI
2. 데이터 패치 관련 로딩
- 영화 목록 불러올 때: 영화 리스트를 서버에서 불러오는 동안 로딩 표시
- 영화 상세 정보 요청 중: 특정 영화 상세 페이지 들어갔을 때 상세 정보 불러오는 중 표시
- 댓글이나 평점 불러오는 중: 댓글, 리뷰 데이터 요청 시 로딩 UI
3. 추가로 로딩 표시하면 좋은 곳
- 검색 결과 로딩 중: 영화 검색 기능에서 결과가 나올 때까지 로딩 표시
- 필터링/정렬 변경 시: 필터나 정렬 버튼 클릭 후 결과가 바뀔 때 로딩 표시
- 영화 예매/구매 요청 처리 중: 예매 버튼 클릭 후 서버 처리 중 로딩 표시
- 사용자 프로필 업데이트 중: 사용자 정보 수정 후 저장하는 중 로딩 표시
- 페이지 전환 시: 큰 페이지 이동(예: 영화 목록 → 상세 페이지) 중 데이터 로딩 시간 길다면 로딩 표시
- 이미지(포스터 등) 로딩 중: 영화 포스터 이미지가 늦게 뜰 때 기본 이미지 + 로딩 UI
부가 팁
- 로딩 상태는 꼭 사용자 행동에 따른 비동기 처리 구간에 넣는 게 중요해요.
- 로딩 표시 없이 화면이 갑자기 깜빡이거나 멈추면 UX가 나빠지니까요.
- 스켈레톤 UI(skeleton screen)도 고려해보세요. 빈 화면 대신 기본 틀 UI 보여주면 더 자연스럽습니다.
그러니까 결국, 이런 곳에 비슷한 부류끼리 공통 로딩 컴포넌트 만들거나, 그 때 그 때 만들어주면 좋을 것 같다.
로딩관련해서 스켈레톤이나, Intersection Observer이 부분 공부해봐야겠다.
그 중,
1. 예를 들어 회원 정보를 받아오는 과정에서, 그 과정은 비동기니까,
좀 늦을 것이나 그런걸 대비해서 로딩 관련 로직을 만들어주는 것도 좋은데
한가지 예시는 다음과 같다.
일반적인 useUser 훅 내부 구조 예시
import { useEffect, useState } from "react";
function useUser() {
const [user, setUser] = useState(null); // 사용자 정보
const [loading, setLoading] = useState(true); // 로딩 상태
useEffect(() => {
const fetchUser = async () => {
try {
const res = await fetch("/api/check-token"); // 예: 토큰 유효성 검사
if (res.ok) {
const userData = await res.json();
setUser(userData); // 로그인된 사용자 정보
} else {
setUser(null); // 로그인 안 됨
}
} catch (err) {
console.error(err);
setUser(null); // 오류 발생 시 로그인 안 된 것으로 처리
} finally {
setLoading(false); // 무조건 로딩 종료
}
};
fetchUser();
}, []);
return { loggedIn: !!user, loading };
}
여기서 로딩은 사용자 정보랑 관련된 전역에서 같이 관리했다. 그 이유는 로그인 상태에 따라서 로딩을 보여줄지 말지 결정하는 것 이기 때문.
핵심 흐름 정리
- 컴포넌트가 처음 렌더링되면 loading은 true.
- fetchUser()가 비동기로 사용자 정보를 받아옴.
- 응답에 따라 user 상태가 업데이트됨.
- 마지막에 setLoading(false)로 로딩 상태 종료.
이걸, 컴포넌트에서 사용하는 방식
const { loggedIn, loading } = useUser();
if (loading) {
return <Spinner />; // 로딩 중 UI
}
return loggedIn ? <Dashboard /> : <LoginPage />;
즉, loading은 단순히 "값이 왔는지 여부"가 아니라, "비동기 처리 중인 상태" 자체를 의미하는 명시적인 상태 변수야.
그리고 useUser 훅 안에서 setLoading(true) → 비동기 처리 → setLoading(false) 구조로 직접 제어하는 게 일반적이야.
위 코드 중 setLoading(false); // 무조건 로딩 종료 이게 무슨 말이지
좋은 질문이야, Jane!
여기서 **"무조건 로딩 종료"**라는 말은 비동기 작업이 성공하든 실패하든, 마지막에는 loading 상태를 false로 바꾼다는 의미야.
try {
// 비동기 작업: 예를 들면 로그인 여부 확인 API 호출
} catch (err) {
// 에러 처리
} finally {
setLoading(false); // ✅ 여기
}
finally 블록이란?
JavaScript에서 try...catch...finally 구문에서 finally는:
- try에서 성공하든
- catch에서 에러가 나든
무조건 실행되는 블록이야.
왜 필요해?
예를 들어 서버에 로그인 여부 확인 요청을 보냈을 때:
- 성공해서 사용자 정보를 받아오면 → setUser(...) 하고 setLoading(false)
- 실패해서 에러가 나도 → setUser(null) 하고 setLoading(false)
이렇게 하면 언제든지 로딩 상태가 끝났다는 걸 확실하게 표시할 수 있어.
요약
setLoading(false); // 무조건 로딩 종료
→ 이건 비동기 작업이 끝났다는 신호를 컴포넌트에 주는 것이고,
→ 로딩 스피너를 멈추게 하는 조건이기도 해.
'Studying > React' 카테고리의 다른 글
리액트 공부하기 - React Router 리액트 라우터 심화공부 (0) | 2025.05.23 |
---|---|
리액트 공부하기 - hooks를 최상단에 작성 해야 하는 이유? 변수에 담아서 사용하는 이유? (0) | 2025.05.22 |
리액트 공부하기 - Protected Route(보호된 라우트) 설정 / 로그인 된 유저만 접근 가능한 페이지 만들기 (0) | 2025.05.22 |
리액트 공부하기 - try ... catch 오류 찾아내기 throw (0) | 2025.05.22 |
리액트 공부하기 - export, import 컴포넌트 내보내기, 불러오기 (0) | 2025.05.22 |