[React] 전역 상태 관리 라이브러리

jiny·2025년 1월 21일

기술 면접

목록 보기
32/78

🗣️ Redux 말고 다른 전역 상태 관리 라이브러리를 사용해 본 적이 있으신가요?

  • 의도: 다양한 상태 관리 라이브러리에 대한 지식과 경험 소개 및 해당 라이브러리를 선택하게 된 구체적인 이유를 설명할 수 있는지 확인하는 질문

  • 나의 답안

    네, 저는 Zustand를 사용해 본 경험이 있습니다.

    Zustand는 Redux보다 훨씬 간결한 문법과 가벼운 구조를 가지고 있어서,
    복잡한 보일러플레이트 없이 전역 상태를 빠르게 구성할 수 있다는 장점이 있습니다.
    특히 Flux 패턴을 강제하지 않고, 훅 기반으로 간단하게 상태를 읽고 수정할 수 있기 때문에, 소규모 프로젝트나 React Query와 같이 비동기 상태 관리 도구와 병행할 때 유용했습니다.

    실제 프로젝트에서는 Zustand를 전역 UI 상태(예: 모달, 로그인 상태 등)에 사용하고, React Query를 서버 상태 관리용으로 함께 사용해 클라이언트와 서버 상태를 명확히 분리했습니다.

  • 주어진 답안 (모범 답안)

    네, 저는 Redux 외에 zustand라는 전역 상태 관리 라이브러리를 사용한 경험이 있습니다.

    기존 Redux와는 다르게 zustand는 보일러 플레이트가 단순하여 더욱 빠른 환경 설정이 가능하다는 장점이 있습니다.
    예를 들어 Redux에서 작성해야 했던 액션, 리듀서, 디스패치, 미들웨어 등 대신에, zustand에서는 create() 메서드를 통해 atomic한 객체를 생성하는 것으로 앞선 과정을 단축할 수 있습니다.

    또한 Redux에서 채택했던 Flux 아키텍처를 그대로 가져와 사용하였기에 이 또한 저에게 아주 큰 매력으로 다가왔습니다.
    왜냐하면 Redux ToolKit을 포함해 Redux를 사용할 때의 가장 큰 장점으로 체감할 수 있었던 것은 바로 개발자 도구(devtool)의 유용함 덕분이었습니다.
    zustand는 Redux의 Flux 아키텍처를 그대로 채택하였기에 기존 Redux의 개발자 도구를 이어서 사용할 수 있게 되었고, 이는 곧 저에게 있어서 더 이상 Redux를 사용해야 할 이유를 모두 잃은 것과 다름없었습니다.


📝 개념 정리

React에서 전역 상태 관리는 애플리케이션의 여러 컴포넌트 간에 데이터를 공유하고 효율적으로 업데이트하기 위해 필요한 개념이다.
React는 기본적으로 단방향 데이터 흐름을 따르며, props를 통해 부모에서 자식으로 데이터를 전달한다.
그러나 이러한 방식은 상태가 여러 컴포넌트에서 필요할 때 비효율적일 수 있다.
이를 해결하기 위해 전역 상태 관리 라이브러리를 사용한다.

🌟 Redux

Redux는 가장 널리 사용되는 상태 관리 라이브러리 중 하나로, 상태를 중앙 저장소(store)에 보관하고 이를 컴포넌트에서 구독(subscribe)할 수 있도록 설게되었다.

  1. 주요 개념
    • Store: 애플리케이션의 전역 상태가 저장되는 곳이다.
    • Action: 상태를 변경하기 위해 발생시키는 객체이다. type과 추가 데이터를 포함한다.
    • Reducer: 액션에 따라 상태를 업데이트하는 순수 함수이다.
    • Dispatch: 액션을 스토어로 전달하여 상태 변경을 트리거한다.
    • Middleware: 액션이 리듀서로 전달되기 전에 처리할 로직을 작성할 수 있다. (예: redux-thunk, redux-saga)
  1. 장점
    • 예측 가능한 상태 관리: 상태 변경이 어디서 발생하는지 명확히 알 수 있다.
    • 디버깅 도구: Redux DevTools를 사용하면 상태 변경 과정을 쉽게 추적할 수 있다.
    • 확장성: 복잡한 애플리케이션에서도 잘 작동한다.
  1. 단점
    • 보일러플레이트 코드: 설정과 액션, 리듀서 작성에 많은 코드가 필요하다.
    • 복잡성: 작은 프로젝트에서는 과도할 수 있다.
  1. 사용 방법

    • 설치

      npm install @reduxjs/toolkit react-redux
    • 설정
      1) 스토어 생성: Redux Toolkit의 configureStore를 사용하여 스토어를 설정한다.

      // store.ts
      import { configureStore } from "@reduxjs/toolkit";
      import counterReducer from "./counterSlice";
      
      export const store = configureStore({
        reducer: {
          counter: counterReducer,
        }
      });
      
      export type RootState = ReturnType<typeof store.getState>;
      export type AppDispatch = typeof store.dispatch;

      2) 리듀서 정의

      // counterSlice.ts
      import { createSlice } from "@reduxjs/toolkit";
      
      const counterSlice = createSlice({
        name: "counter",
        initialState: { value: 0 },
        reducers: {
          increment: (state) => {
            state.value += 1;
          },
          decrement: (state) => {
            state.value -= 1;
          },
          incrementByAmount: (state, action) => {
            state.value += action.payload;
          },
        },
      });
      
      export const { increment, decrement, incrementByAmount } = counterSlice.actions;
      export default counterSlice.reducer;

      3) React 컴포넌트에서 사용

      // Counter.tsx
      import React from "react";
      import { useSelector, useDispatch } from "react-redux";
      import { increment, decrement } from "./counterSlice";
      import { RootState } from "./store";
      
      export default function Counter() {
        const count = useSelector((state: RootState) => state.counter.value);
        const dispatch = useDispatch();
        
        return (
          <div>
            <button onClick={() => dispatch(decrement())}>-</button>
            <span>{count}</span>
            <button onClick={() => dispatch(increment())}>+</button>
          </div>
        );
      }

🌟 Zustand

Zustand는 간단하면서도 강력한 상태 관리 라이브러리로, Redux의 대안으로 떠오르고 있다.
훨씬 간결한 API를 제공한다.

  1. 주요 개념
    • 상태를 정의하고 직접 수정할 수 있는 작은 스토어
    • React 컴포넌트와 밀접하게 작동하며, 훅(Hooks) 기반으로 설계되었다.
  1. 장점
    • 간단한 설정: Redux와 달리 보일러플레이트 코드가 거의 없다.
    • 사용하기 쉬운 API: React 상태처럼 상태를 정의하고 관리할 수 있다.
    • Context API 대비 성능 우수: 불필요한 렌더링을 방지한다.
  1. 단점
    • 특정 상황에서는 대규모 상태 관리가 어려울 수 있다.
    • Redux에 비해 커뮤니티와 생태계가 상대적으로 작다.
  1. 사용 방법

    • 설치

      npm install zustand
    • 설정 및 사용

      // store.ts
      import create from "zustand";
      
      interface CounterState {
        count: number;
        increment: () => void;
        decrement: () => void;
      }
      
      const useStore = create<CounterState>((set) => ({
        count: 0,
        increment: () => set((state) => ({ count: state.count + 1 })),
        decrement: () => set((state) => ({ count: state.count - 1 })),
      }));
      
      export default useStore;
    • React 컴포넌트에서 사용

      // Counter.tsx
      import React from "react";
      import useStore from "./store";
      
      export default function Counter() {
        const { count, increment, decrement } = useStore();
        
        return (
          <div>
            <button onClick={decrement}>-</button>
            <span>{count}</span>
            <button onClick={increment}>+</button>
          </div>
        );
      }

🌟 Context API

React에 내장된 상태 관리 도구로, 컴포넌트 트리 전체에서 데이터를 공유할 수 있도록 한다.

  1. 주요 개념
    • Provider: 데이터를 제공하는 컴포넌트이다. 모든 자식 컴포넌트가 이 데이터를 구독할 수 있다.
    • Consumer: 데이터를 소비하는 컴포넌트이다.
    • useContext: Consumer 없이 데이터를 가져오기 위한 React Hook이다.
  1. 장점
    • 내장 API로 추가적인 설치가 필요 없다.
    • 소규모 프로젝트에 적합하다.
  1. 단점
    • 렌더링 성능 문제: 상태가 변경되면 모든 하위 컴포넌트가 다시 렌더링된다.
    • 대규모 상태 관리에는 적합하지 않다.
  1. 사용 방법

    • 설정 및 사용

      // CounterContext.tsx
      import React, { createContext, useContext, useState } from "react";
      
      const CounterContext = createContext<any>(null);
      
      export function CounterProvider({ children }: { children: React.ReactNode }) {
        const [count, setCount] = useState(0);
        
        return (
          <CounterContext.Provider value={{ count, setCount }}>
            {children}
          </CounterContext.Provider>
        );
      }
      
      export function useCounter() {
        return useContext(CounterContext);
      }
    • React 컴포넌트에서 사용

      // Counter.tsx
      import React from "react";
      import { useCounter } from "./CounterContext";
      
      export default function Counter() {
        const { count, setCount } = useCounter();
        
        return (
          <div>
            <button onClick={() => setCount(count - 1)}>-</button>
            <span>{count}</span>
            <button onClick={() => setCount(count + 1)}>+</button>
          </div>
        );
      }
      
      // App.tsx
      import React from "react";
      import { CounterProvider } from "./CounterContext";
      import Counter from "./Counter";
      
      export default function App() {
        return (
          <CounterProvider>
            <Counter />
          </CounterProvider>
        );
      }

🌟 Recoil

Recoil은 Facebook에서 만든 라이브러리로, React의 상태 관리 경험을 개선하는 데 중점을 둔다.

  1. 주요 개념
    • Atom: 상태의 기본 단위이다. 다른 컴포넌트에서 구독할 수 있다.
    • Selector: 파생된 상태를 생성하거나 상태를 변환한다.
  1. 장점
    • React와 깊이 통합된다.
    • 비동기 상태 관리가 간단하다.
    • 컴포넌트 간 독립적인 상태 구독이 가능하다.
  1. 단점
    • 안정화 단계가 진행 중인 라이브러리로, 일부 기능은 제한적일 수 있다.
    • Redux보다 커뮤니티가 작다.
  1. 사용 방법

    • 설치

      npm install recoil
    • 설정 및 사용

      // recoil/atoms.ts
      import { atom } from "recoil";
      
      export const counterState = atom({
        key: "counterState",
        default: 0,
      });
    • React 컴포넌트에서 사용

      // Counter.tsx
      import React from "react";
      import { useRecoilState } from "recoil";
      import { counterState } from "./recoil/atoms";
      
      export default function Counter() {
        const [count, setCount] = useRecoilState(counterState);
        
        return (
          <div>
            <button onClick={() => setCount(count - 1)}>-</button>
            <span>{count}</span>
            <button onClick={() => setCount(count + 1)}>+</button>
          </div>
        );
      }

🌟 MobX

MobX는 상태를 관찰하고 자동으로 업데이트하는 데 초점을 맞춘 라이브러리이다.

  1. 주요 개념
    • Observable: 상태를 정의하는 객체이다.
    • Action: 상태를 변경하는 메서드이다.
    • Computed: 상태에서 파생된 값을 계산한다.
    • Reaction: 상태 변경에 따라 특정 로직을 실행한다.
  1. 장점
    • 선언적인 코드: 간단한 상태 관리를 위해 적합하다.
    • 비동기 상태 관리가 자연스럽게 처리된다.
  1. 단점
    • React 외 다른 프레임워크에서도 사용할 수 있는 만큼 React에 특화된 기능이 부족하다.
    • 코드 구조가 다소 직관적이지 않을 수 있다.
  1. 사용 방법

    • 설치

      npm install mobx mobx-react-lite
    • 설정 및 사용

      // store.ts
      import { makeAutoObservable } from "mobx";
      
      class CounterStore {
        count = 0;
        
        constructor() {
          makeAutoObservable(this);
        }
        
        increment() {
          this.count += 1;
        }
        
        decrement() {
          this.count -= 1;
        }
      }
      
      export const counterStore = new CounterStore();
    • React 컴포넌트에서 사용

      // Counter.tsx
      import React from "react";
      import { observer } from "mobx-react-lite";
      import { counterStore } from "./store";
      
      const Counter = observer(() => {
        return (
          <div>
            <button onClick={() => counterStore.decrement()}>-</button>
            <span>{counterStore.count}</span>
            <button onClick={() => counterStore.increment()}>+</button>
          </div>
        );
      });
      
      export default Counter;

🌟 Jotai

Jotai는 최소한의 API와 코드로 전역 상태를 관리할 수 있는 라이브러리이다.

  1. 주요 개념
    • 상태를 정의하는 atom과 이를 사용하는 간단한 API를 제공한다.
  1. 장점
    • 간결함: 복잡한 설정 없이 사용할 수 있다.
    • TypeScript 친화적이다.
  1. 단점
    • 특정 상황에서 복잡한 상태 관리가 어려울 수 있다.
  1. 사용 방법

    • 설치

      npm install jotai
    • 설정 및 사용

      // store.ts
      import { atom } from "jotai";
      
      export const counterAtom = atom(0);
    • React 컴포넌트에서 사용

      // Counter.tsx
      import React from "react";
      import { useAtom } from "jotai";
      import { counterAtom } from "./store";
      
      export default function Counter() {
        const [count, setCount] = useAtom(counterAtom);
        
        return (
          <div>
            <button onClick={() => setCount(count - 1)}>-</button>
            <span>{count}</span>
            <button onClick={() => setCount(count + 1)}>+</button>
          </div>
        );
      }

🌟 TanStack Query

상태 관리보다는 서버 상태 관리에 초점이 맞춰진 라이브러리이다.

  1. 주요 개념
    • 데이터 fetching, 캐싱, 동기화를 지원한다.
    • 주로 비동기 데이터를 다룰 때 사용한다.
  1. 장점
    • 서버 데이터 상태를 쉽게 관리한다.
    • 자동 캐싱 및 데이터 업데이트
  1. 단점
    • 클라이언트 상태 관리에는 적합하지 않다.

🌟 정리

  • 작은 프로젝트: Context API, Zustand, Jotai
  • 중간 규모 프로젝트: Redux, Recoil
  • 서버 상태 관리: TanStack Query
  • 대규모 프로젝트: Redux, MobX

0개의 댓글