리액트에서의 독립적인 상태 저장소: Redux와 Zustand (2)

최정환·2024년 1월 14일
0

최근 리액트 애플리케이션에서의 상태 관리에 대해 많은 변화가 일어나고 있습니다. 다양한 라이브러리들이 등장했지만, 그 중에서도 특히 주목받는 것이 Zustand입니다.
Zustand는 상태 관리를 놀라울 정도로 간결하게 만들어주며, React 컴포넌트 트리와의 독립성을 유지합니다.

이 글에서는 Zustand의 작동 방식과 이 라이브러리가 어떻게 상태 관리를 단순화하는지에 대해 살펴보겠습니다.

Zustand

Zustand는 리액트 애플리케이션의 상태 관리를 위한 라이브러리로, React의 Context API에 의존하지 않고 독립적으로 상태를 관리합니다.

리액트 컴포넌트와 완전히 분리되어 있으며, 전역 상태를 간편하게 생성하고 사용할 수 있습니다.


공식 깃헙 코드

1. React Store 생성


export const create = (<T>(createState: StateCreator<T, [], []> | undefined) =>
  createState ? createImpl(createState) : createImpl) as Create

create는 store를 생성하는 함수입니다. 만약 createState를 인자로 받는다면 createImpl을 호출합니다.

const createImpl = <T>(createState: StateCreator<T, [], []>) => {

  // createStore 실제 상태 저장소를 생성하는 함수
  const api =
    typeof createState === 'function' ? createStore(createState) : createState

  // 선택적으로 상태의 특정 부분을 선택(selector)하고, 선택된 부분의 동일성을 판단하는 함수(equalityFn)를 제공
  const useBoundStore: any = (selector?: any, equalityFn?: any) =>
    useStore(api, selector, equalityFn)

  // useBoundStore 함수 객체에 api 객체의 속성과 메서드를 복사
  Object.assign(useBoundStore, api)

  return useBoundStore
}

createStore는 리액트 말고도 여러 라이브러리에서 사용 가능한 바닐라에서 받아옵니다.

2. Vanilla Store 생성

const createStoreImpl: CreateStoreImpl = (createState) => {
  // 상태 저장소의 상태 타입
  type TState = ReturnType<typeof createState>
  // 상태 변화를 감지하는 함수로, 새로운 상태와 이전 상태를 매개변수로 받습니다.
  type Listener = (state: TState, prevState: TState) => void
  
  let state: TState
  const listeners: Set<Listener> = new Set()

  // 상태를 변경하는 함수, 상태 변경시 모든 Listener에 알림
  const setState: StoreApi<TState>['setState'] = (partial, replace) => {
    
    const nextState =
      typeof partial === 'function'
        ? (partial as (state: TState) => TState)(state)
        : partial
    if (!Object.is(nextState, state)) {
      const previousState = state
      state =
        replace ?? (typeof nextState !== 'object' || nextState === null)
          ? (nextState as TState)
          : Object.assign({}, state, nextState)
      listeners.forEach((listener) => listener(state, previousState))
    }
  }

  // 현재 상태를 반환
  const getState: StoreApi<TState>['getState'] = () => state

  // 상태 변화를 구독할 새 리스너를 추가하는 함수
  const subscribe: StoreApi<TState>['subscribe'] = (listener) => {
    listeners.add(listener)
    // Unsubscribe
    return () => listeners.delete(listener)
  }


  const api = { setState, getState, subscribe, destroy }
  // 상태 저장소의 초기 상태를 설정
  state = createState(setState, getState, api)
  return api as any
}

// createImpl이 사용하는 createStore  
export const createStore = ((createState) =>
  createState ? createStoreImpl(createState) : createStoreImpl) as CreateStore

바닐라 zustand의 set, get, subscribe 와 같은 기능들이 들어있는 객체로 store를 만듭니다.

결론

React에서 Redux를 사용하기 위해, react-redux 라이브러리는 React의 Context API를 사용하여 "브릿지"를 만듭니다.

이를 통해 React 컴포넌트 트리 전반에 걸쳐 Redux 스토어에 접근할 수 있습니다.

이와 반대로 zustand는 리액트를 위해 만들어진 라이브러리인 만큼 vallina에 있는 store를 만드는 함수를 이용해 만든 후 직접적으로 상태 저장소에 접근할 수 있는 훅(useStore 등)을 제공합니다.

이 훅을 통해 React 컴포넌트에서 Zustand 상태 저장소의 상태를 구독하고 업데이트할 수 있습니다.

0개의 댓글

관련 채용 정보