junsobi

Menu

Close

Zustand를 활용한 로컬 스토리지 상태 관리

Zustand를 활용하여 로컬 스토리지에 상태를 저장하고 불러오는 방법을 알아봅니다.

List

이미지

Zustand로 로컬 스토리지 상태 관리하기

프론트엔드 개발에서 상태 관리는 필수적인 요소입니다. 특히, 사용자의 데이터가 새로고침 이후에도 유지되어야 한다면 로컬 스토리지(LocalStorage)를 활용하는 것이 좋은 방법입니다. 하지만, 로컬 스토리지를 직접 다루다 보면 데이터 직렬화/역직렬화, 예외 처리 등의 불편함이 따릅니다.

이 문제를 해결하기 위해 Zustand의 persist 미들웨어를 활용하면 간편하게 상태를 로컬 스토리지에 저장하고 불러올 수 있습니다.


1️⃣ Zustand + LocalStorage 기본 구조

persist 미들웨어 활용

Zustand에서는 persist 미들웨어를 활용하여, 상태를 자동으로 로컬 스토리지에 저장하고 불러올 수 있습니다. 이를 통해 사용자의 상태가 유지되도록 보장할 수 있습니다.

다음은 zustandpersist를 활용한 로컬 스토리지 상태 관리 예제입니다.

import { create } from 'zustand';
import { persist } from 'zustand/middleware';
 
const useDrawingStore = create(
  persist(
    (set) => ({
      tool: 'free-draw',
      setTool: (tool) => set({ tool }),
      thickness: 5,
      setThickness: (thickness) => set({ thickness }),
      color: '#000000',
      setColor: (color) => set({ color }),
      shapes: [],
 
      addShape: (shape) =>
        set((state) => ({
          shapes: [...state.shapes, shape]
        }))
    }),
    {
      name: 'drawing-storage' // 로컬 스토리지에 저장될 키 값
    }
  )
);

📌 persist 미들웨어 동작 방식

  1. Zustand의 create() 내부에서 persist 미들웨어를 사용하면 자동으로 상태를 로컬 스토리지에 저장합니다.
  2. name 옵션을 설정하면 해당 키 값으로 로컬 스토리지에서 데이터를 관리합니다.
  3. 새로고침이 되더라도 Zustand가 로컬 스토리지에서 자동으로 데이터를 불러와 상태를 복원합니다.

2️⃣ 안전한 LocalStorage 핸들링

Zustand의 persist 미들웨어는 기본적으로 로컬 스토리지를 다룰 때 예외 처리를 제공하지만, 보다 안전한 저장/불러오기 로직을 구현하고 싶다면 직접 핸들링하는 것도 좋은 방법입니다.

다음은 safeLocalStorage 유틸을 활용하여 직접 로컬 스토리지를 다루는 방법입니다.

const safeLocalStorage = {
  getItem: (key: string) => {
    if (typeof window === 'undefined') return null;
    try {
      const item = localStorage.getItem(key);
      return item ? JSON.parse(item) : null;
    } catch (error) {
      console.error(`로컬 스토리지 키 "${key}"를 읽는 중 오류 발생:`, error);
      return null;
    }
  },
  setItem: (key: string, value: unknown) => {
    if (typeof window === 'undefined') return;
    try {
      localStorage.setItem(key, JSON.stringify(value));
    } catch (error) {
      console.error(
        `로컬 스토리지 키 "${key}"를 저장하는 중 오류 발생:`,
        error
      );
    }
  },
  removeItem: (key: string) => {
    if (typeof window === 'undefined') return;
    localStorage.removeItem(key);
  }
};

이제 Zustand 스토어에서 persiststorage 옵션을 설정하여 이 유틸을 사용할 수 있습니다.

export const useDrawingStore = create(
  persist(
    (set) => ({
      tool: 'free-draw',
      setTool: (tool) => set({ tool }),
      thickness: 5,
      setThickness: (thickness) => set({ thickness }),
      color: '#000000',
      setColor: (color) => set({ color }),
      shapes: []
    }),
    {
      name: 'drawing-storage',
      storage: safeLocalStorage // 커스텀 로컬 스토리지 핸들러 사용
    }
  )
);

🚀 효과

  • 로컬 스토리지를 안전하게 관리 가능
  • JSON 파싱 에러 및 undefined 오류 방지
  • 서버 사이드 렌더링(SSR) 환경에서도 안전하게 동작

3️⃣ Zustand로 상태 관리가 더 편한 이유

기존에는 로컬 스토리지를 직접 다루려면 다음과 같은 과정이 필요했습니다.

  1. localStorage.setItem()localStorage.getItem()을 직접 호출해야 함
  2. 상태가 변경될 때마다 로컬 스토리지를 갱신해야 함
  3. JSON 직렬화 및 역직렬화를 수동으로 관리해야 함
  4. 새로고침 후 데이터를 불러오는 로직을 따로 구현해야 함

하지만 Zustand의 persist 미들웨어를 사용하면 위의 과정이 모두 자동으로 처리되므로, 개발자의 부담이 줄어듭니다.

✅ Zustand + persist의 장점

  • 자동 상태 저장: 상태가 변경될 때 자동으로 로컬 스토리지에 반영됨
  • 새로고침 후 자동 복원: 상태를 수동으로 복원할 필요 없음
  • 코드 간결화: useStateuseEffect로 관리하는 것보다 훨씬 직관적
  • 미들웨어 활용: persist 외에도 devtools 등 다양한 미들웨어를 쉽게 추가 가능

✨ 마무리

Zustand의 persist 미들웨어를 활용하면 별다른 설정 없이도 상태를 로컬 스토리지에 저장하고 불러올 수 있어 매우 편리합니다. 또한, safeLocalStorage와 같은 유틸을 활용하면 더욱 안전한 상태 관리를 할 수 있습니다.

React에서 상태를 유지해야 하는 경우, Zustand + LocalStorage 조합은 강력한 선택지가 될 수 있습니다. 간단한 설정으로 상태 관리와 데이터 영속성을 동시에 해결할 수 있으니, 프로젝트에 적극적으로 도입해 보세요! 🚀


관련 프로젝트 저장소 : https://github.com/junsobi/DrawingTool-with-KonvaReact