React Query와 Zustand를 활용한 효율적인 상태 관리 가이드

0

현대 React 애플리케이션에서 서버 상태와 클라이언트 상태를 효율적으로 관리하는 것은 중요한 과제입니다. 이를 해결하기 위해 React Query와 Zustand와 같은 라이브러리를 사용할 수 있습니다. 이 글에서는 React Query와 Zustand를 사용하여 상태 관리를 간단하고 직관적으로 처리하는 방법을 단계별로 알아보겠습니다.

1. React Query 소개 및 사용법

React Query는 서버 상태를 쉽게 관리할 수 있도록 도와주는 라이브러리입니다. 이를 통해 데이터 페칭, 캐싱, 동기화, 서버 상태 업데이트 등의 작업을 간단하게 처리할 수 있습니다.

설치

npm install @tanstack/react-query
npm install @tanstack/react-query-devtools

설정

먼저 QueryClient를 설정하고, 애플리케이션을 QueryClientProvider로 감싸야 합니다.

import React from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';

const queryClient = new QueryClient();

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      {/* Your app components go here */}
      <ReactQueryDevtools initialIsOpen={false} />
    </QueryClientProvider>
  );
}

export default App;

데이터 페칭

`useQuery` 훅을 사용하여 데이터를 페칭할 수 있습니다.

import React from 'react';
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';

const fetchUsers = async () => {
  const { data } = await axios.get('https://jsonplaceholder.typicode.com/users');
  return data;
};

function Users() {
  const { data, error, isLoading } = useQuery(['users'], fetchUsers);

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <div>
      {data.map(user => (
        <div key={user.id}>
          {user.name} - {user.email}
        </div>
      ))}
    </div>
  );
}

export default Users;

Mutation 사용

데이터를 수정하거나 삭제하는 작업은 `useMutation` 훅을 사용하여 처리할 수 있습니다.

import React from 'react';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import axios from 'axios';

const addUser = async (newUser) => {
  const { data } = await axios.post('https://jsonplaceholder.typicode.com/users', newUser);
  return data;
};

function AddUser() {
  const queryClient = useQueryClient();
  const mutation = useMutation(addUser, {
    onSuccess: () => {
      queryClient.invalidateQueries(['users']);
    },
  });

  const handleAddUser = () => {
    mutation.mutate({ name: 'New User', email: 'newuser@example.com' });
  };

  return (
    <div>
      <button onClick={handleAddUser}>
        {mutation.isLoading ? 'Adding...' : 'Add User'}
      </button>
      {mutation.isError && <div>Error: {mutation.error.message}</div>}
      {mutation.isSuccess && <div>User added!</div>}
    </div>
  );
}

export default AddUser;

2. Zustand 소개 및 사용법

Zustand는 React 애플리케이션에서 상태 관리를 간단하고 직관적으로 할 수 있게 도와주는 상태 관리 라이브러리입니다.

설치

npm install zustand

상태 스토어 생성

import create from 'zustand';

const useStore = create((set) => ({
  count: 0,
  increase: () => set((state) => ({ count: state.count + 1 })),
  decrease: () => set((state) => ({ count: state.count - 1 })),
}));

export default useStore;

상태 사용

import React from 'react';
import useStore from './store';

function Counter() {
  const { count, increase, decrease } = useStore();

  return (
    <div>
      <h1>{count}</h1>
      <button onClick={increase}>Increase</button>
      <button onClick={decrease}>Decrease</button>
    </div>
  );
}

export default Counter;

미들웨어 사용

상태 변경 시 로컬 스토리지에 저장하는 예제입니다.

import create from 'zustand';
import { persist } from 'zustand/middleware';

const useStore = create(persist(
  (set) => ({
    count: 0,
    increase: () => set((state) => ({ count: state.count + 1 })),
    decrease: () => set((state) => ({ count: state.count - 1 })),
  }),
  {
    name: 'counter-storage',
  }
));

export default useStore;

DevTools 사용

Redux DevTools와의 통합을 지원합니다.

import create from 'zustand';
import { devtools } from 'zustand/middleware';

const useStore = create(devtools((set) => ({
  count: 0,
  increase: () => set((state) => ({ count: state.count + 1 })),
  decrease: () => set((state) => ({ count: state.count - 1 })),
})));

export default useStore;

3. 실제 예제 코드

React Query와 Zustand를 함께 사용하여 상태를 관리하는 전체 예제입니다.

import React from 'react';
import create from 'zustand';
import { QueryClient, QueryClientProvider, useQuery } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import axios from 'axios';

const queryClient = new QueryClient();

const useStore = create((set) => ({
  count: 0,
  name: 'Zustand',
  increase: () => set((state) => ({ count: state.count + 1 })),
  decrease: () => set((state) => ({ count: state.count - 1 })),
  setName: (newName) => set(() => ({ name: newName })),
}));

const fetchUsers = async () => {
  const { data } = await axios.get('https://jsonplaceholder.typicode.com/users');
  return data;
};

function Users() {
  const { data, error, isLoading } = useQuery(['users'], fetchUsers);

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <div>
      {data.map(user => (
        <div key={user.id}>
          {user.name} - {user.email}
        </div>
      ))}
    </div>
  );
}

function Counter() {
  const { count, name, increase, decrease, setName } = useStore();

  return (
    <div>
      <h1>{count}</h1>
      <h2>{name}</h2>
      <button onClick={increase}>Increase</button>
      <button onClick={decrease}>Decrease</button>
      <button onClick={() => setName('New Zustand Name')}>Change Name</button>
    </div>
  );
}

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <Counter />
      <Users />
      <ReactQueryDevtools initialIsOpen={false} />
    </QueryClientProvider>
  );
}

export default App;

4. 상태 관리 모범 사례 및 결론

  • 단순화된 상태 모델: 상태 모델을 단순화하고, 가능한 한 적은 상태로 애플리케이션을 관리합니다.
  • 분리된 관심사: 상태 관리 로직을 컴포넌트 로직과 분리하여 유지보수성을 높입니다.
  • 효율적인 데이터 페칭: 필요한 경우에만 데이터를 페칭하고, 데이터 캐싱을 활용하여 성능을 최적화합니다.
  • 비동기 작업 관리: 비동기 작업을 적절히 처리하여 UI의 일관성을 유지합니다.

이렇게 React Query와 Zustand를 함께 사용하면, 서버 상태와 클라이언트 상태를 효율적으로 관리하여 React 애플리케이션의 성능과 유지보수성을 높일 수 있습니다. 이제 이 가이드를 참고하여 여러분의 프로젝트에 적용해보세요!

Leave a Reply