React Query 완벽 가이드: 서버 상태 관리의 시작
목차
1. React Query란?
React Query는 React 애플리케이션에서 서버 상태 관리를 쉽게 할 수 있게 도와주는 라이브러리입니다.
주요 특징
- 서버 데이터 캐싱
- 로딩/에러 상태 자동 관리
- 페이지네이션 및 무한 스크롤 지원
- 데이터 자동 업데이트
- TypeScript 지원
2. 설치 및 설정
설치
bash
1npm install @tanstack/react-query2# or3yarn add @tanstack/react-query4기본 설정5typescriptCopyimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';ts
1// QueryClient 인스턴스 생성2const queryClient = new QueryClient();3
4function App() {5 return (6 <QueryClientProvider client={queryClient}>7 <MainApp />8 </QueryClientProvider>9 );10}3. 기본 사용법
ts
1useQuery: 데이터 조회2typescriptCopyfunction UserProfile() {3 const { data, isLoading, error } = useQuery({4 queryKey: ['user', userId],5 queryFn: () => axios.get(`/api/users/${userId}`)6 });7
8 if (isLoading) return <div>로딩중...</div>;9 if (error) return <div>에러 발생!</div>;10
11 return <div>{data.name}의 프로필</div>;12}13useMutation: 데이터 변경14typescriptCopyfunction CreateUserForm() {15 const mutation = useMutation({16 mutationFn: (newUser) => axios.post('/api/users', newUser),17 onSuccess: () => {18 alert('사용자가 생성되었습니다!');19 }20 });21
22 const handleSubmit = (data) => {23 mutation.mutate(data);24 };25
26 return <form onSubmit={handleSubmit}>...</form>;27}4. 실제 사용 예시
ts
1로그인 기능 구현2typescriptCopyfunction LoginScreen() {3 const loginMutation = useMutation({4 mutationFn: (credentials) => axios.post('/api/login', credentials),5 onSuccess: (data) => {6 // 토큰 저장7 localStorage.setItem('token', data.token);8 // 메인 페이지로 이동9 navigate('/main');10 },11 onError: (error) => {12 alert(error.message);13 }14 });15
16 const handleLogin = (e) => {17 e.preventDefault();18 loginMutation.mutate({19 email,20 password21 });22 };23
24 return (25 <form onSubmit={handleLogin}>26 <input type="email" value={email} onChange={e => setEmail(e.target.value)} />27 <input type="password" value={password} onChange={e => setPassword(e.target.value)} />28 <button type="submit" disabled={loginMutation.isLoading}>29 {loginMutation.isLoading ? '로그인 중...' : '로그인'}30 </button>31 </form>32 );33}ts
1무한 스크롤 구현2typescriptCopyfunction InfinitePostList() {3 const {4 data,5 fetchNextPage,6 hasNextPage,7 isFetchingNextPage8 } = useInfiniteQuery({9 queryKey: ['posts'],10 queryFn: ({ pageParam = 1 }) => 11 axios.get(`/api/posts?page=${pageParam}`),12 getNextPageParam: (lastPage) => lastPage.nextPage13 });14
15 return (16 <div>17 {data.pages.map((page) => (18 page.posts.map((post) => (19 <PostItem key={post.id} post={post} />20 ))21 ))}22 23 <button24 onClick={() => fetchNextPage()}25 disabled={!hasNextPage || isFetchingNextPage}26 >27 {isFetchingNextPage28 ? '로딩중...'29 : hasNextPage30 ? '더 보기'31 : '마지막 페이지'}32 </button>33 </div>34 );35}5. 성능 최적화 팁
ts
11. 적절한 캐싱 설정2typescriptCopyconst queryClient = new QueryClient({3 defaultOptions: {4 queries: {5 staleTime: 1000 * 60 * 5, // 5분6 cacheTime: 1000 * 60 * 30, // 30분7 },8 },9});102. 선택적 데이터 가져오기11typescriptCopyconst { data } = useQuery({12 queryKey: ['user', userId],13 queryFn: () => fetchUserData(userId),14 enabled: !!userId, // userId가 있을 때만 실행15});163. 낙관적 업데이트 사용17typescriptCopyconst mutation = useMutation({18 mutationFn: updateTodo,19 onMutate: async (newTodo) => {20 // 이전 쿼리 취소21 await queryClient.cancelQueries(['todos']);22
23 // 이전 값 저장24 const previousTodos = queryClient.getQueryData(['todos']);25
26 // 낙관적으로 새 값 설정27 queryClient.setQueryData(['todos'], (old) => [...old, newTodo]);28
29 // 롤백을 위한 컨텍스트 반환30 return { previousTodos };31 },32 onError: (err, newTodo, context) => {33 // 에러 시 롤백34 queryClient.setQueryData(['todos'], context.previousTodos);35 }36});6. 자주 묻는 질문
Q: React Query vs Redux의 차이점은? A: Redux는 클라이언트 상태 관리에 적합하고, React Query는 서버 상태 관리에 특화되어 있습니다. 두 라이브러리는 상호 보완적으 로 사용될 수 있습니다. Q: 캐시된 데이터를 수동으로 갱신하려면? A: queryClient.invalidateQueries()를 사용하여 캐시를 무효화하거나, refetch()를 호출하여 데이터를 다시 가져올 수 있습니다. Q: 오프라인 지원이 가능한가요? A: React Query는 기본적으로 오프라인 상황을 고려하여 설계되었습니다. 오프라인 상태에서도 캐시된 데이터를 사용할 수 있으며, 온라인 상태가 되면 자동으로 데이터를 동기화합니다. 마치며 React Query는 서버 상태 관리의 복잡성을 크게 줄여주는 강력한 도구입니다. 기본적인 설정만으로도 많은 기능을 제공하며, 필요에 따라 세밀한 설정도 가능합니다. 이 가이드가 React Query를 시작하는 데 도움이 되었기를 바랍니다. 더 자세한 내용은 공식 문서를 참조해주세요.