❓ Information

  • defining zustand store

❗ Relevant data

πŸ“¦ Information Resources

heropy.dev: zustand μ„€λͺ…

velog: zustand useAuthStore

πŸ”° Content ->

Store 생성

create<νƒ€μž…>()
import { create } from 'zustand'
 
export const useCountStore = create<{
  count: number
  increase: () => void
  decrease: () => void
}>(set => ({
  count: 1,
  increase: () => set(state => ({ count: state.count + 1 })),
  decrease: () => set(state => ({ count: state.count - 1 }))
}))

Store μ‚¬μš©

μ•‘μ…˜ μ‚¬μš© 방식

useCountStore(...) 방식이 있고, useCountStore.getState() 방식이 μžˆλ‹€. λ‘˜ λ‹€ store 의 κΈ°λŠ₯을 μ •μƒμ μœΌλ‘œ μ‚¬μš©ν•˜λŠ” 것이닀.

그런데 μ»΄ν¬λ„ŒνŠΈ λ‚΄λΆ€μ—μ„œλŠ” useCountStore(...)λ₯Ό μ‚¬μš©ν•œλ‹€. μ΄μœ λŠ” μ»΄ν¬λ„ŒνŠΈμ˜ λ¦¬λ Œλ”λ§μ„ μœ„ν•΄μ„œμ΄λ‹€.

useUserStore.getState() λŠ” ν˜„μž¬ μƒνƒœ 객체λ₯Ό μ¦‰μ‹œ κ°€μ Έμ˜€κΈ° λ•Œλ¬Έμ— 값이 λ°”λ€Œμ–΄λ„ λ¦¬λ Œλ”λ§μ΄ μ•ˆλœλ‹€ λ”°λΌμ„œ λΉ„UI 둜직 μ—μ„œλŠ” useCountStore.getState() λ₯Ό μ‚¬μš©ν•˜λŠ” 것이닀.

뢀가적 포인트

  • zustandλŠ” λ‚΄λΆ€μ μœΌλ‘œ vanilla storeλ₯Ό μ œκ³΅ν•˜κ³ , useUserStoreλŠ” κ·Έ μœ„μ— React Hook을 μž…νžŒ 것
  • κ·Έλž˜μ„œ λ Œλ”λ§ μ—°κ²° 여뢀에 따라 두 κ°€μ§€ 방식 쀑 μ„ νƒν•˜λŠ” κ±°μ§€, κΈ°λŠ₯μ μœΌλ‘œλŠ” 같은 storeλ₯Ό 바라보고 있음

μ•‘μ…˜ ν•˜λ‚˜μ”© κ°€μ Έμ˜€κΈ°

store λ₯Ό μ‚¬μš©ν•˜λŠ” λͺ¨λ“  μ»΄ν¬λ„ŒνŠΈμ˜ λΆˆν•„μš”ν•œ λ¦¬λ Œλ”λ§μ„ λ°©μ§€ν•˜κΈ° μœ„ν•΄, μ»΄ν¬λ„ŒνŠΈμ—μ„œλŠ” ν•œ λ²ˆμ— ν•˜λ‚˜μ”©λ§Œ μƒνƒœ(μ•‘μ…˜)을 가져와야함

import { useCountStore } from './store/count'
 
export default function App() {
  const count = useCountStore(state => state.count)
  const increase = useCountStore(state => state.increase)
  const decrease = useCountStore(state => state.decrease)
  return (
    <>
      <h2>{count}</h2>
      <button onClick={increase}>+1</button>
      <button onClick={decrease}>-1</button>
    </>
  )
}

닀쀑 μƒνƒœ 선택(useShallow)

useShallow훅을 μ‚¬μš©ν•˜λ©΄ μ—¬λŸ¬ μƒνƒœ(μ•‘μ…˜)을 ν•œ λ²ˆμ— κ°μ²΄λ‚˜ λ°°μ—΄λ‘œ κ°€μ Έμ˜¬ 수 μžˆλ‹€

import { useShallow } from 'zustand/shallow'
import { useCountStore } from './store/count'
 
export default function App() {
  // 객체
  // const { count, increase, decrease } = useCountStore(state => ({
  const countState = useCountStore(
    useShallow(state => ({
      count: state.count,
      increase: state.increase,
      decrease: state.decrease
    }))
  )
  
  return (
    <>
      <h2>{countState.count}</h2>
      <button onClick={countState.increase}>+1</button>
      <button onClick={countState.decrease}>-1</button>
    </>
  )
}
import { useShallow } from 'zustand/shallow'
import { useCountStore } from './store/count'
 
export default function App() {
  // λ°°μ—΄
  // const [count, increase, decrease] = useCountStore(
  const countState = useCountStore(
    useShallow(state => [state.count, state.increase, state.decrease])
  )
  
  return (
    <>
      <h2>{countState[0]}</h2>
      <button onClick={countState[1]}>+1</button>
      <button onClick={countState[2]}>-1</button>
    </>
  )
}

μ•‘μ…˜ 뢄리

μ—¬λŸ¬ μ»΄ν¬λ„ŒνŠΈμ—μ„œ 단일 μŠ€ν† μ–΄μ˜ μ•‘μ…˜μ„ 많이 μ‚¬μš©ν•œλ‹€λ©΄, μ•‘μ…˜μ„ 뢄리해 κ΄€λ¦¬ν•˜λŠ” νŒ¨ν„΄μ„ ν™œμš©ν•  수 있음. λ‹€μŒκ³Ό 같이 actions 객체 μ•ˆμ—μ„œ λͺ¨λ“  μ•‘μ…˜μ„ κ΄€λ¦¬ν•˜λ©΄, 각 μ»΄ν¬λ„ŒνŠΈμ—μ„œ ν•„μš”ν•œ μ•‘μ…˜λ§Œ κ°€μ Έμ˜€κΈ° 쉬움

import { create } from 'zustand'
 
export const useCountStore = create<{
  count: number
  actions: {
    increase: () => void
    decrease: () => void
  }
}>(set => ({
  count: 1,
  actions: {
    increase: () => set(state => ({ count: state.count + 1 })),
    decrease: () => set(state => ({ count: state.count - 1 }))
  }
}))
import { useCountStore } from './store/count'
 
export default function App() {
  const count = useCountStore(state => state.count)
  const { increase, decrease } = useCountStore(state => state.actions)
  return (
    <>
      <h2>{count}</h2>
      <button onClick={increase}>+1</button>
      <button onClick={decrease}>-1</button>
    </>
  )
}

zustand has middleware devtools, persist

devtools

What it does

From Chrome extention redux-devtools Zustand store can be shown

How to use

  1. Wrap the create function with devtools as the first parameter.
  2. Set the store name as the second parameter of devtools.
import create from 'zustand';
import { devtools } from 'zustand/middleware';
 
const useStore = create(
	devtools(
		(set) => ({
			// ...
		}), { name: "CounterStore" }
	)
);

persist

What it does

Saves state inside browser storage (ex: localStorege, sessionStorage, IndexedDB). So page Refreshing, app restarting won’t wipe the data.

How to use

  1. Wrap the create function with persist
  2. Set the store name, storage to use, etc as the second parameter of devtools.
import create from 'zustand';
import { persist } from 'zustand/middleware';
 
const useState = create(
	persist(
		(set) => ({
			count: 0,
			increment: () => set((state) => ({ count: state.count + 1 })),
		}),
		{
			name: 'count-storage', // μ €μž₯μ†Œμ— μ €μž₯될 ν‚€ 이름
			storage: createJSONStorage(() => localStorage), // μ‚¬μš©ν•  μ €μž₯μ†Œ
			partialize: (store) => ({ count: store.count }). // 둜컬 μŠ€ν† λ¦¬μ§€μ— μ €μž₯ν•  μƒνƒœλ§Œ 선택
		}
	)
);