Zustand

Zustand

npm install zustand
  • 'zustand'๋Š” ๋…์ผ์–ด๋กœ 'state'๋ผ๋Š” ๋œปํ•œ๋‹ค.

  • ๊ฐ„์†Œํ™”๋œ Flux ์›์น™์„ ๋”ฐ๋ฅด๋ฉฐ ์ž‘๊ณ  ํ™•์žฅ ๊ฐ€๋Šฅํ•œ ์ตœ์†Œํ•œ์˜ ์ƒํƒœ ๊ด€๋ฆฌ ์†”๋ฃจ์…˜

  • Redux์™€ ๊ต‰์žฅํžˆ ์œ ์‚ฌํ•˜์ง€๋งŒ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ƒํƒœ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด Reducer, Actions, Dispatch๋ฅผ ๋งŒ๋“ค์–ด์•ผํ•˜๋Š” Redux์™€ ๋‹ฌ๋ฆฌ Zustand๋Š” ๊ต‰์žฅํžˆ ๊ฐ„๋‹จํ•˜๋‹ค.

  • Hooks๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌ

์žฅ์ 

  • Boiler plate ์ฝ”๋“œ๊ฐ€ ๊ต‰์žฅํžˆ ์ ๋‹ค.

  • Context Provider๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†์–ด ๋”์šฑ ๊ฐ„๋‹จํ•ด์ง€๊ณ  ๊ฐ€๋…์„ฑ์ด ๋†’์•„์ง„๋‹ค.

Store ์ƒ์„ฑํ•˜๊ธฐ

  • Store๋Š” Hooks์œผ๋กœ ๋˜์–ด์žˆ์œผ๋ฉฐ, Store ์•ˆ์—๋Š” ๊ฐ์ฒด, ํ•จ์ˆ˜ ๋“ฑ ๋ฌด์—‡์ด๋“  ๋„ฃ์„ ์ˆ˜ ์žˆ๋‹ค.

  • ์ œ๊ณต๋˜๋Š” create ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Store๋ฅผ ์ƒ์„ฑ

  • set ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•œ๋‹ค.

import create from 'zustand';

export const useCounterStore = create((set) => ({
  count: 1,
  increase: () => set((state) => ({ count: state.count + 1 }))
}))
import { useCounterStore } from '@/store';

export const Counter = () => {
  const { count, increase } = useCounterStore();
  
  return (
    <button type="button" onClick={increase}>{count}</button>
  )
}

Persist Middleware

์ƒํƒœ๋ฅผ local storage์— ์ €์žฅํ•˜์—ฌ ์ƒˆ๋กœ๊ณ ์นจ ํ•ด๋„ ๊ฐ’์„ ์œ ์ง€ํ•˜๋„๋ก ์„ค์ •ํ•ด๋ณด์ž.

import create from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';

export const useCounterStore = create(
  persist((set) => ({
    count: 1,
    increase: () => set((state) => ({ count: state.count + 1 }))
  }),
  { 
    name: 'counter'
    storage: createJSONStorage(() => sessionStorage)
  })
)

Persist Options

  • name: local storage key๊ฐ’์„ ์ง€์ •

  • storage: ์ €์žฅํ•  ์Šคํ† ๋ฆฌ์ง€๋ฅผ ์ง€์ •ํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค. (๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€, ์„ธ์…˜ ์Šคํ† ๋ฆฌ์ง€)

    • default -> createJSONStorage(() => localStorage)

  • partialize -> ์ €์žฅํ•  ์ƒํƒœ์˜ ์ผ๋ถ€๋งŒ์„ ์Šคํ† ๋ฆฌ์ง€์— ๊ด€๋ฆฌํ• ์ง€ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • onRehydrationStorage -> ์Šคํ† ๋ฆฌ์ง€๊ฐ€ ์ˆ˜ํ™”๋  ๋•Œ ํ˜ธ์ถœ๋  ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ์ง€์ •

  • merge -> ๋ฏธ๋“ค์›จ์–ด๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์–•์€ ๋ณ‘ํ•ฉ์„ ์ˆ˜ํ–‰, ํ•ด๋‹น ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊นŠ์€ ๋ณ‘ํ•ฉ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • skipHydration -> ๊ธฐ๋ณธ์ ์œผ๋กœ ์ดˆ๊ธฐํ™”์‹œ hydration์ด ์‹คํ–‰๋˜๋Š”๋ฐ ํŠน์ • ์ƒํ™ฉ์˜ ๊ฒฝ์šฐ ์ฒซ hydration ์‹œ๊ธฐ๋ฅผ ์ œ์–ดํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. ๋‹จ, ์ˆ˜๋™์œผ๋กœ rehydrate()๋ฅผ ์‹คํ–‰์‹œ์ผœ์ฃผ์–ด์•ผ ํ•œ๋‹ค.

DevTools

Zustand๋Š” Redux DevTools๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

import create from 'zustand';
import { devtools } from 'zustand/middleware';

export const useCounterStore = create(
  devtools((set) => ({
    count: 1,
    increase: () => set((state) => ({ count: state.count + 1 }))
  }), 
)

/**
let counterStore = (set) => ({
  count: 1,
  increase: () => set((state) => ({ count: state.count + 1 }))
});

counterStore = devtools(counterStore);
counterStore = persist(counterStore, { name: 'counter' });

export const useCounterStore = create(counterStore) 
**/

Async

zustand๋Š” ์ž‘์—…์ด ๋™๊ธฐ์ธ์ง€ ๋น„๋™๊ธฐ์ธ์ง€ ์‹ ๊ฒฝ์“ฐ์ง€ ์•Š๋Š”๋‹ค. ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” set ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.

const useStore = create((set) => ({
  item: {},
  fetch: async (pond) => {
    const response = await axios.get('/foo');
    set({ item: response.data }) 
  }
}))

Last updated