본문 바로가기

개발/React.js

전역 상태 관리 라이브러리 - Zustand vs Recoil

요약

최근까지만 해도 Recoil이 공식적으로 SSR을 지원하지 않았는데, 최근 문서에 SSR 대처 방안을 업데이트 해주었다.

알아본 김에 Zustand와 Recoil의 장단점과 특성을 파악하면 적재적소에 활용하기 좋을 것 같아 개인적인 호기심으로 조사해보았다.

 

알아보게 된 계기

이전 프로젝트를 진행하며 서버 사이드와 클라이언트 사이드 데이터가 불일치하는 문제로 인해 쿠키, 세션을 활용하여 이슈를 해결하셨던 부분을 인지하고 있었다. 분명 이와 같은 상황이 다른 개발자들도 있었을 것으로 판단하여 더 나은 해결 방법이 없는지 확인하던 중 zustand로 해결했다는 어느 포스팅을 발견 후 본격적으로 알아보기 시작하였다.

jotai는 월등히 좋다면야 알아보겠지만 지금으로서는 recoil, zustand만 알아봐도 충분하기에 점유율 정도만 훑어보고 넘기려고 한다.

🤔 Zustand의 장점

  1. 서버와 클라이언트 간 상태 동기화: Zustand는 서버와 클라이언트 모두에서 동일한 상태를 생성하고 관리할 수 있다. 이는 서버와 클라이언트 사이에서 상태 불일치를 방지하는 데 도움이 된다.
  2. Hydrate/Dehydrate 기능: Zustand는 상태를 "dehydrate"하여 문자열로 직렬화하고, 이를 다시 "hydrate"하여 상태로 복원하는 기능을 제공한다. 이 기능을 사용하면 SSR에서 생성된 상태를 클라이언트로 전송하고, 클라이언트에서 이 상태를 초기 상태로 사용할 수 있다. 이러한 방법으로 SSR과 CSR 사이에서 데이터 불일치 문제를 해결할 수 있다.
  3. 간결하고 유연한 API: Zustand의 API는 간결하며, 커스텀 훅을 사용하여 상태 관리 로직을 캡슐화할 수 있다. 이는 코드 재사용성을 높이고, 상태 관리 코드를 분리하여 유지 관리를 용이하게 한다.
  4. 최적화: Zustand는 불필요한 리렌더링을 방지하고 성능을 최적화하는데 도움이 된다. Zustand는 상태가 변경될 때만 컴포넌트를 리렌더링하므로, 불필요한 리렌더링을 최소화할 수 있다.

🤔 그렇다면, Recoil만으로는 서버/클라이언트 상태 통일이 불가능한가? → 최근 문서에 의하면 가능해졌다.

state를 클라이언트(local storage, session storage)에 저장하고 싶다면 recoil-persist 라이브러리를 사용하면 된다. 그리고, Recoil이 불과 최근까지는 SSR을 지원하지 않았지만, 나름 대처 방안을 마련하여(Custom hook 활용) 문서에 해당 항목이 추가되었다.

https://github.com/polemius/recoil-persist#server-side-rendering

 

기존에 우리 사용하던 recoil이 아무래도 러닝 커브가 낮기도 하고, 무엇보다 React 팀이 만든 라이브러리이기 때문에 신뢰도가 높은 점은 나머지 단점을 상쇄할 정도로 무시할 수 없는 장점이다. 그러나, Next.js를 사용하는 개발자들이 많아진 이상 SSR과 CSR 사이의 hydration 문제점을 빠르고 간결하게 해결할 수 있는 전역 상태 관리 라이브러리가 필요해진건 기정 사실이다. 그래서 Recoil과 Zustand의 장단이 무엇이 있는지에 대해 인지하고, 상황에 따라 적재 적소에 사용하면 좋을 것 같다.

Zustand - 장단점

장점 1. redux-dev-tools를 활용하여 디버깅 가능

장점 2. Provider로 컴포넌트를 감싸주지 않아도 사용 가능

장점 3. 상태가 변경될 때만 컴포넌트를 렌더링

장점 4. Redux와 같은 Flux 패턴으로 동작

Flux 패턴이란?

Facebook에서 개발한 애플리케이션 아키텍처 패턴. 단방향 데이터 흐름을 사용하여 상태를 관리한다.

Flux 아키텍처는 크게 네 가지 주요 구성 요소로 구성된다.

  1. Action: 애플리케이션에서 데이터를 변경할 수 있는 유일한 방법은 action을 통한 것이다. Action은 애플리케이션에서 일어날 수 있는 모든 유형의 이벤트 또는 사용자 상호작용을 나타낸다.
  2. Dispatcher: Dispatcher는 모든 action이 통과하는 중앙 허브이다. Action이 생성되면 Dispatcher를 통해 Store로 전달된다.
  3. Store: Store는 애플리케이션의 상태와 로직을 포함한다. Store는 Dispatcher를 통해 전달된 Action을 수신하고, 해당 Action에 따라 상태를 업데이트한다.
  4. View: View는 사용자 인터페이스를 나타내며, Store의 상태를 기반으로 렌더링된다. Store의 상태가 변경되면 View는 자동으로 업데이트된다.

Zustand - Count 예제

→ Provider로 감싸주지 않고 바로 사용이 가능하며 문법이 간단한 클로저 방식이라는 것이 포인트이다.

// store/countStore.tsx

export const useCountStore = create((set) => ({
    count: 0,
    increaseCount: () => set((state: number) => ({count: state.count + 1})),
    removeAllCounts: () => set({count: 0}),
}));
// app/page.tsx
import {useCountStore} from "@/stores/countStore";

export const ZustandTestPage = () => {
    const count = useCountStore((state) => state.count);
    const increaseCount = useCountStore((state) => state.increaseCount);
    const removeAllCounts = useCountStore((state) => state.removeAllCounts);

    return (
        <div className="text-center">
            <h1>Test Zustand !</h1>
            <div>
                <button onClick={increaseCount} className="bg-white p-4 text-black">count is {count}</button>
            </div>
            <div>
                <button onClick={removeAllCounts}>remove counts</button>
            </div>
        </div>
    )
}

Recoil이 Zustand보다 좋은 점

 

위의 나열한 항목들만 보면 Zustand가 타 라이브러리에 의존적이지도 않고, 문법도 간결하고, 사용법도 간결하고 장점만 있는 것은 아닌가 라고 생각할 수 있지만 장단점이 존재할 수 밖에 없다. 아무리 쉬운 문법이라 하더라도 초기에는 적응하는데에 시간이 걸릴 것이며, 현업에서는 저마다의 상황과 사정이 있으므로 어느 라이브러리가 독보적으로 좋다고 얘기할 수는 없다. 따라서, Zustand보다 우리가 현재 사용하고 있는 Recoil의 장점은 무엇인지 톺아보겠다.

  1. 원자적 상태 관리: Recoil은 원자(Atom)와 선택자(Selector)라는 두 가지 핵심 개념을 사용하여 상태를 관리한다. 이를 통해 Recoil은 더 세분화된 상태 관리를 할 수 있으며, 상태 간의 의존성을 효과적으로 다룰 수 있다.
  2. Derived State: Recoil의 Selector를 사용하면, 다른 상태 값에 기반한 파생 상태를 만들 수 있다. 이는 계산된 상태를 만들거나, 비동기 작업을 수행하는 데 유용하다.
  3. Concurrent Mode Compatibility: Recoil은 React의 Concurrent 모드와 호환되어, 더 나은 사용자 경험과 성능을 제공할 수 있다.
  4. 디버깅 툴: Recoil은 Recoilize와 같은 디버깅 도구를 제공하여 애플리케이션의 상태를 시각적으로 확인하고 디버깅하는 데 도움이 된다. (아직 해본적은 없긴 하다.)
  5. 호환성 보장: Recoil은 Facebook에서 개발하고 지원하므로, 커뮤니티 지원과 차세대 React 기능에 대한 호환성이 보장된다.

'개발 > React.js' 카테고리의 다른 글

Xlsx parsing + react-table  (0) 2024.09.13
OAuth 인증 - 인가에 대하여  (0) 2024.09.13
파일 Drag & Drop  (0) 2024.09.13
Excel 파싱 관련  (0) 2024.09.13
React Storybook 사용 방법  (0) 2024.09.13