Zustand

기존에 사용하던 상태관리 Recoil은 React를 개발한 Meta에서 개발하고 관리하는 라이브러이다.

최근데 이 Recoil 관련해서 업데이트를 사실상 중단한게 아닌가라는 글들을 많이 보게 되었다.

이유로는 깃허브의 issue및 PR이 쌓이지만, 코멘트는 없고 1년간 패치가 두번 밖에 되지 않았으며, Recoil을 사용하면서 메모리 누수와 같은 성능적인 문제가 있는데도 불구하고 고쳐지지 않고 있다고 한다.

그래서 Recoil을 대체할 다른 상태관리 라이브러리를 찾던 중 Zustand를 알게 되었다.

Zustand는 가벼운 패키지 라이브러리로 초기 세팅값이 매우 적어서 사용하기 매우 편리하다.

공식 홈페이지에도 Zustand 소개로 작고, 빠르고, 확장이 쉬운 상태 관리 라고 소개하고 있다.

가벼운 상태관리 였던 Recoil은 20kb정도였는데 Zustand는 번들 사이즈는 1.2kb로 매우 가볍다.

세팅

  1. 설치
pnpm isntall zustand

zustand는 설치만 하면 Provider 없이 바로 사용할 수 있다. 기존에 사용하던 Recoil은 RecoilRoot로 감싸줘야 했기때문에 더 빠르게 세팅을 끝낼 수 있다.



상태 만들기

src/store.ts
import { create } from 'zustand';

interface State {
  count: number;
}

const initialState: State = { count: 0 };

export const useCountStore = create<State >(() => ({
  ...initialState,
}));

위와 같이 초기값을 세팅하고, create 함수를 사용하여 상태를 만들어 준다.

초기값을 따로 세팅하는 이유는 나중에 reset을 할 때 초기값으로 돌아가기 위함이다.

app/page.tsx
export default function Home() {
  const { count } = useCountStore();

  return <p>{count}</p>;
}

값을 사용할때는 위와 같이 useCountStore를 사용하여 값을 가져올 수 있다.

zustand는 위와 같이 store를 가져오면 모든 값을 가져오기 때문에 여러값이 있을때, 원하는 값만 가져오려면 아래와 같이 사용할 수 있다

app/page.tsx
export default function Home() {
  const count = useCountStore((state) => state.count);

  return <p>{count}</p>;
}

이렇게 하면 count값만 가져올 수 있다.



상태 변경하기

set

src/store.ts
import { create } from 'zustand';

interface State {
  count: number;
}

interface Actions {
  actions: {
    setCount: (count: number) => void;
    increment: () => void;
    decrement: () => void;
    reset: () => void;
  };
}

const initialState: State = { count: 0 };

export const useCountStore = create<State & Actions>(set => ({
  ...initialState,
  actions: {
    setCount: (count: number) => set({ count }),
    increment: () => set(state => ({ count: state.count + 1 })),
    decrement: () => set(state => ({ count: state.count - 1 })),
    reset: () => set(initialState),
  },
}));

함수들을 actions으로 묶어서 관리의 용이성을 높이려고 했다.

set을 통해서 값을 변경할 수 있다.

app/page.tsx
export default function Home() {
  const { count, actions } = useCountStore();

  return (
    <div>
      <p>{count}</p>
      <button onClick={actions.increment}>+</button>
      <button onClick={actions.decrement}>-</button>
      <button onClick={actions.reset}>reset</button>
    </div>
  );
}

위와 같이 값을 변경할때에는 set만 사용하면 되었는데, 만약 원본 상태를 변경하지 않고 같을 출력하려면 get을 통해서 store의 상태를 가져와서 사용할 수 있다.

2. get

src/store.ts
import { create } from 'zustand';

interface State {
  count: number;
}

interface Actions {
  actions: {
    setCount: (count: number) => void;
    increment: () => void;
    decrement: () => void;
    reset: () => void;
  };
}

const initialState: State = { count: 1 };

export const useCountStore = create<State & Actions>((set, get) => ({
  ...initialState,
  actions: {
    setCount: (count: number) => set({ count }),
    dobble: () => {
        const count = get().count;
        return count * 2;
      }
  },
}));
app/page.tsx
export default function Home() {
  const count = useCountStore((state) => state.count);
  const doubbleCount = useCountStore((state) => state.actions.dobble);

  return (
    <div>
      <p>{count}</p>
      <p>{doubbleCount}</p>
    </div>
  );
}

위와 같이 get을 사용하여 값을 가져와서 원본 값을 변경하지 않고 사용할 수 있다.