Programming Language/React

[React] Zustand: 여러 상태를 사용할 때 하지말아야 할 것

개발자참치 2024. 10. 1. 17:34

이 글을 쓰게 된 배경은

zustand의 z자도 모르고 썼던게 분명한 내가 잘못 사용해왔던 코드에 대한 깨달음과 부끄러움을 담은 글이다.

(위 글은 Zustand의 최신 버전인 v5로 작성되었다)

여러 상태를 사용할 때 하지말아야 할 것

Not To Do: 구조 분해 할당으로 가져오기

import { create } from 'zustand'

const useEqpStore = create((set) => ({
  type: 'printer',
  state: 'idle',
  process: 'none',
  subprocess: 'none',
  updateType: (newType) => set({ type: newType }),
  updateState: (newState) => set({ state: newState }),
  updateProcess: (newProcess) => set({ process: newProcess }),
  updateSubprocess: (newSubprocess) => set({ subprocess: newSubprocess }),
}))

// Not To Do: 구조 분해 할당으로 불러오기
function EquipmentStatus() {
  const { type, state } = useEqpStore()

  return (
    <div>
      <p>Type: {type}</p>
      <p>State: {state}</p>
    </div>
  )
}

문제점:  const { type, state } = useEqpStore()와 같이 사용할 때,

실제로는 type과 state만 사용하지만 store의 모든 상태를 가져오게 된다.

 

=> process나 subprocess가 변경될 때도 불필요한 리렌더링을 유발하여, 성능 저하로 이어질 수 있다.

Zustand의 올바른 사용

0. 기본 사용

// To Do: 필요한 상태만 각각 불러와서 사용하기
function EquipmentStatus() {
  const type = useEqpStore((state) => state.type)
  const state = useEqpStore((state) => state.state)

  return (
    <div>
      <p>Type: {type}</p>
      <p>State: {state}</p>
    </div>
  )
}

리렌더링이 되지 않게 하려면, 코드가 길어지는 불편함을 감수하더라도

필요한 개별 상태를 각각 불러와야하는 것이 기본적인 사용법이라고 할 수 있다.

하지만, store로 부터 가져오는 상태가 1~2개도 아니고 굉장히 많게되면 코드의 가독성 또한 좋지 않게 되기에, 

공식문서에서 제안하는 방법은 아래와 같다.

1.  useShallow

// v5
// To Do: useShallow 활용

import { useShallow } from "zustand/shallow";

function EquipmentStatus() {
  const { type, state } = useEqpStore(
    useShallow((state) => ({
      type: state.type,
      state: state.state,
    }))
  )

  return (
    <div>
      <p>Type: {type}</p>
      <p>State: {state}</p>
    </div>
  )
}

2. createWithEqualityFn(with shallow)

// v5
// To Do: createWithEqualityFn + shallow 활용

import { createWithEqualityFn as create } from 'zustand/traditional'
import { shallow } from 'zustand/shallow'

const useEqpStore = create((set) => ({
  type: 'printer',
  state: 'idle',
  process: 'none',
  subprocess: 'none',
  updateType: (newType) => set({ type: newType }),
  updateState: (newState) => set({ state: newState }),
  updateProcess: (newProcess) => set({ process: newProcess }),
  updateSubprocess: (newSubprocess) => set({ subprocess: newSubprocess }),
}))

function EquipmentStatus() {
  const { type, state } = useEqpStore(
    (state) => ({
      type: state.type,
      state: state.state,
    }),
    shallow
  )

  return (
    <div>
      <p>Type: {type}</p>
      <p>State: {state}</p>
    </div>
  )
}

참고자료

1. 공식문서1(기본 ReadMe)

 

GitHub - pmndrs/zustand: 🐻 Bear necessities for state management in React

🐻 Bear necessities for state management in React. Contribute to pmndrs/zustand development by creating an account on GitHub.

github.com

2. 공식문서2(v4 to v5)

3. stackoverflow

 

Fetching multiple states with Zustand/React (shorthand syntax)

Are both ways of fetching states from the Zustand store identical in respect of re-renders on state changes? Method described in the documentation: const nuts = useStore(state => state.nuts) const

stackoverflow.com

 

https://github.com/pmndrs/zustand/blob/main/docs/guides/updating-state.md#with-immer