[React] Zustand

사용법

설치

yarn add zustand

 

store 생성

1) zustand 폴더 > bearsStore.js 생성

 

2) zustand의 create를 사용해 스토어 생성 (이 때 스토어는 관리할 상태에 따라 여러개가 될 수 있음)

import { create } from 'zustand';

const useBearStore = create((set) => {
  return {
    bears: 0,
    increase: function() {
      set(function(state) {
        return {
          bears: state.bears + 1
        }
      })
    },
    // 초기화용 함수
    init: function (){
      set({
        bears: 0,
      })
    }
  }
});

 

store를 받아와 사용

const App = () {
  const bears = useBearsStore(function(state) {
    return state.bears;
  });
  
  const increase = useBearsStore(function(state){
    return state.increase;
  });
  
  // 혹은 구조분해할당 활용
  const { bears, increase } = useBearsStore(function(state){
    return state;
  });
  
  return (
    <div>
      <h2>{ bears }</h2>
      <button onClick={ increase }> +1 </button>
    </div>
  )
}

 

 

immer 사용해 불변성 유지하기

 위 예시는 불변성을 어기는 예시로, 구조분해할당/map/filter 등 새로운 배열이나 객체를 반환하는 방법을 사용하는 방법과 immer를 활용하는 방법을 사용할 수 있다.

 

설치

yarn add immer

 

 

store의 set을 immer로 감싸주기

import { immer } from 'zustand/middleware/immer'

const useTodoStore = create(immer(set) => { ... })

이렇게 사용하고 위 캡쳐 예시처럼 push 등을 활용해 불변성을 지키지 않는 것처럼 코드를 작성해도 내부적으로 처리를 해준다

 

 

persist 사용해 새로고침시에도 데이터 유지하기

immer를 감싸거나, immer를 사용하지 않는 경우라면 store를 만들 때 set 부분을 감싸주고 함수가 끝나는 부분에 로컬 혹은 세션 스토리지에 저장할 이름(name)을 지정해줘야 함

import { produce } from "immer";
import { create } from "zustand";
import { persist } from "zustand/middleware";

const useTodosStore = create(
  persist(
    (set) => ({
      todos: [
        {
          id: 1,
          title: "Learn Zustand",
          tasks: [{ id: 1, task: "Read documentation", done: false }],
        },
      ],
      addTask: (todoId, newTask) =>
        set(
          produce((state) => {
            const todo = state.todos.find((todo) => todo.id === todoId);
            if (todo) {
              todo.tasks.push(newTask); // 불변성 깨짐: 직접 수정
            }
            // return { todos: state.todos }; // 변경된 참조가 기존 상태와 같아 리렌더링되지 않음
          })
        ),
      toggleTask: (todoId, taskId) =>
        set(
          produce((state) => {
            const todo = state.todos.find((todo) => todo.id === todoId);
            if (todo) {
              const task = todo.tasks.find((task) => task.id === taskId);
              if (task) {
                task.done = !task.done; // 불변성 깨짐: 직접 수정
              }
            }
            // return { todos: state.todos }; // 변경된 참조가 기존 상태와 같아 리렌더링되지 않음
          })
        ),
    }),
    {
      name: "todos-storage", // 저장소 이름을 설정해요!
      // getStorage: () => sessionStorage, // localStorage가 아닌 곳에 저정하고 싶다면!
    }
  )
);

export default useTodosStore;