본문 바로가기
Dev/React

React 상태 관리: 깊이 있게 파헤치기

by ZEROGOON 2024. 11. 10.

왜 상태 관리가 필요할까?

React 컴포넌트는 자체적인 상태를 가지고 있지만, 앱의 규모가 커지고 컴포넌트 간의 상호 작용이 복잡해질수록 단순한 상태 관리로는 한계가 드러납니다. 이러한 문제를 해결하기 위해 상태 관리 라이브러리나 패턴을 활용합니다.

  • Props Drilling: 깊은 계층의 컴포넌트에 데이터를 전달하기 위해 중간 컴포넌트들을 거쳐야 하는 문제
  • 글로벌 상태 관리: 앱 전역에서 사용되는 데이터를 효율적으로 관리하기 어려움
  • 복잡한 상태 업데이트 로직: 상태 변화에 따라 여러 컴포넌트를 업데이트해야 할 때 로직이 복잡해짐

상태 관리 라이브러리 종류

  • Redux: 가장 대표적인 상태 관리 라이브러리로, 예측 가능한 상태 흐름을 제공하고 중앙 집중식으로 상태를 관리합니다.
  • Context API: React의 기본적인 상태 관리 API로, 간단한 상태 공유에 적합합니다.
  • Recoil: 원자적인 상태 관리를 지원하며, 셀렉터를 통해 데이터를 추출하고 변환할 수 있습니다.
  • Zustand: 간결하고 유연한 상태 관리 라이브러리로, Redux보다 가볍고 배우기 쉽습니다.
  • Jotai: Recoil과 유사한 기능을 제공하며, 더욱 간단한 API를 제공합니다.

Redux 예제

import { createStore } from 'redux';

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

// reducer 함수
const reducer = (state = initialState, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return { ...state, count: state.count + 1 };
    case 'DECREMENT':
      return { ...state, count: state.count - 1 };
    default:
      return state;
  }
};

// store 생성
const store = createStore(reducer);

// 컴포넌트에서 사용
import React from 'react';
import { connect } from 'react-redux';

const Counter = ({ count, increment, decrement }) => {
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
};

const mapStateToProps = state => ({
  count: state.count
});

const mapDispatchToProps = dispatch => ({
  increment: () => dispatch({ type: 'INCREMENT' }),
  decrement: () => dispatch({ type: 'DECREMENT' })
});

export default connect(mapStateToProps, mapDispatchToProps)(Counter);

 

Context API 예제

import React, { createContext, useState } from 'react';

const CountContext = createContext();

function CounterProvider({ children }) {
  const [count, setCount] = useState(0);

  return (
    <CountContext.Provider value={{ count, setCount }}>
      {children}
    </CountContext.Provider>
  );
}

function Counter() {
  const { count, setCount } = useContext(CountContext);

  return (
    // ...
  );
}

 

Recoil 예제

import { atom, useRecoilState } from 'recoil';

const countAtom = atom({
  key: 'countAtom',
  default: 0
});

function Counter() {
  const [count, setCount] = useRecoilState(countAtom);

  return (
    // ...
  );
}

 

어떤 상태 관리 라이브러리를 선택해야 할까?

  • Redux: 복잡한 애플리케이션, 예측 가능한 상태 흐름이 필요한 경우
  • Context API: 간단한 상태 공유, 작은 앱에 적합
  • Recoil, Zustand, Jotai: 원자적인 상태 관리, 함수형 업데이트, 셀렉터 기능이 필요한 경우

선택 시 고려해야 할 요소:

  • 앱의 규모: 작은 앱은 Context API, 큰 앱은 Redux나 Recoil
  • 팀의 경험: 팀원들이 익숙한 라이브러리
  • 프로젝트 요구사항: 상태 관리의 복잡성, 성능 요구사항 등

결론

상태 관리 라이브러리는 앱의 규모와 복잡도에 따라 적절하게 선택해야 합니다. 각 라이브러리는 고유한 장단점을 가지고 있으며, 어떤 라이브러리를 선택하느냐에 따라 개발 생산성과 코드 품질에 큰 영향을 미칠 수 있습니다.