개발 방법론 & 아키텍쳐

클라이언트 상태 관리(feat. React)

atomicdev 2024. 10. 2. 15:29
728x90

클라이언트 상태 관리

리액트에서 전역 상태 관리는 매우 중요합니다. 이를 효과적으로 관리하기 위한 다양한 방법들이 있는데, 그 중 많이 사용되는 방법이 Context API외부 라이브러리를 활용하는 것입니다. 대표적인 라이브러리로는 Redux, Zustand, Recoil 등이 있습니다. 이 글에서는 각각의 방법들을 비교하고, 상황에 맞는 선택 기준과 예제를 통해 어떻게 적용할 수 있는지 살펴보겠습니다.

클라이언트 상태 관리


1. Context API와 Redux 비교

Context API는 리액트 자체에서 제공하는 기능으로, props drilling 없이 컴포넌트 트리에서 데이터를 공유할 수 있는 방법입니다. 간단한 전역 상태 관리에는 유용하지만, 복잡한 상태를 다루기에는 아쉬운 점이 있을 수 있습니다.

Context API와 Redux 비교 표

항목 Context API Redux
목적 Props drilling 없이 데이터 공유 복잡한 상태를 중앙에서 관리
복잡성 비교적 단순하고 코드를 줄일 수 있음 복잡, 보일러플레이트 코드가 많음
성능 작은 애플리케이션에 적합 큰 애플리케이션에서 최적화가 잘 됨
커스터마이징 옵션 커스터마이징 가능 미들웨어를 통해 커스터마이징 가능

고민이 필요한 부분

  • 로그인 상태토글 값처럼 비교적 단순한 전역 상태를 관리할 때는 Context API가 적합할 수 있습니다.
  • 그러나 복잡한 상태나 여러 곳에서 상태를 효율적으로 공유해야 하는 경우, Redux 같은 라이브러리를 사용하는 것이 효율적입니다.

Context API의 단점

  • Context API의 큰 단점 중 하나는 값이 바뀔 때, 해당 값을 사용하는 모든 컴포넌트가 리렌더링된다는 것입니다. 이 경우 불필요한 리렌더링이 발생할 수 있기 때문에 성능에 악영향을 줄 수 있습니다.

2. Zustand

Zustand는 Context API의 단점을 보완하면서도 사용이 간편한 상태 관리 라이브러리입니다. 상태를 관리하는 간단한 코드 구조와 함께 리액트 컴포넌트에서 쉽게 전역 상태에 접근할 수 있도록 해줍니다.

Zustand의 장점

  1. 간편한 상태 관리: Context API보다 가벼운 코드로 상태 관리를 할 수 있으며, Redux처럼 복잡한 설정 없이도 상태 관리가 가능합니다.
  2. 불필요한 리렌더링 최소화: 상태가 바뀔 때마다 특정 컴포넌트만 리렌더링할 수 있도록 처리할 수 있습니다.
  3. 미들웨어 지원: Redux처럼 미들웨어를 통해 다양한 기능을 추가할 수 있습니다.

Zustand 예제

// Zustand를 사용하여 전역 상태를 관리하는 예제
import create from 'zustand';

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

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

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increase}>Increase</button>
      <button onClick={reset}>Reset</button>
    </div>
  );
}

export default Counter;

위 코드에서 볼 수 있듯이, Zustand는 매우 간단하게 전역 상태를 관리할 수 있으며, 불필요한 리렌더링을 방지합니다.


3. Redux 예제

Redux는 규모가 큰 애플리케이션에서 중앙에서 상태를 관리할 때 적합합니다. 액션, 리듀서, 스토어 등 구조가 다소 복잡하지만, 복잡한 상태를 관리할 수 있는 강력한 기능을 제공합니다.

// Redux 사용 예제
import { createStore } from 'redux';

// 초기 상태 정의
const initialState = {
  count: 0
};

// 리듀서 함수
function counterReducer(state = initialState, action) {
  switch (action.type) {
    case 'INCREASE':
      return { ...state, count: state.count + 1 };
    case 'RESET':
      return { ...state, count: 0 };
    default:
      return state;
  }
}

// 스토어 생성
const store = createStore(counterReducer);

// 액션 생성 함수
const increase = () => ({ type: 'INCREASE' });
const reset = () => ({ type: 'RESET' });

// 컴포넌트에서 상태 사용
function Counter() {
  const count = store.getState().count;

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => store.dispatch(increase())}>Increase</button>
      <button onClick={() => store.dispatch(reset())}>Reset</button>
    </div>
  );
}

export default Counter;

Redux는 복잡한 상태 관리를 할 수 있도록 도와주지만, 보일러플레이트 코드가 많아 초기 설정이 번거로울 수 있습니다.


결론

리액트 프로젝트에서 전역 상태 관리 방법을 선택할 때는 애플리케이션의 복잡도성능 최적화 요구사항을 고려해야 합니다.

  • 간단한 상태 관리에는 Context API 또는 Zustand가 적합할 수 있습니다.
  • 복잡한 상태를 중앙에서 관리할 필요가 있다면 Redux를 사용하는 것이 좋습니다.

각 방법의 장단점을 이해하고, 상황에 맞는 선택을 하는 것이 효율적인 리액트 애플리케이션 개발의 핵심입니다.

728x90