이 글을 쓰게 된 배경은
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>
)
}
참고자료
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
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