Zustand는 React 애플리케이션에서 간단하고 효율적인 상태 관리를 제공하는 라이브러리이다. Redux보다 가볍고, 보일러플레이트코드(Boilerplate Code)가 적어 간편하게 사용할 수 있다.
shallow
비교 가능)persist
, subscribe
등)npm install zustand
1) 상태 스토어 생성
// store.jsx
import { create } from 'zustand';
const useStore = create((set) => ({
count: 0,
increase: () => set((state) => ({ count: state.count + 1 })),
decrease: () => set((state) => ({ count: state.count - 1 })),
}));
useStore
는 상태를 관리하는 훅입니다.
count
는 상태 값이고, increase
와 decrease
는 상태를 변경하는 함수입니다.
2) React컴포넌트에서 사용
// Counter.jsx
import React from 'react';
import { useStore } from './store'; // 위에서 만든 Zustand 스토어를 불러옴
const Counter = () => {
const { count, increase, decrease } = useStore();
//객체 구조 분해 할당
return (
<div>
<h1>Count: {count}</h1>
<button onClick={increase}>+</button>
<button onClick={decrease}>-</button>
</div>
);
};
export default Counter;
useStore
를 사용하여 상태 값을 가져오고 버튼 클릭 시 상태를 변경한다.import React, { createContext, useContext, useState } from "react";
const CountContext = createContext();
const CountProvider = ({ children }) => {
const [count, setCount] = useState(0);
return (
<CountContext.Provider value={{ count, setCount }}>
{children}
</CountContext.Provider>
);
};
const Display = () => {
const { count } = useContext(CountContext);
console.log("Display 리렌더링!");
return <h1>Count: {count}</h1>;
};
const Button = () => {
const { setCount } = useContext(CountContext);
console.log("Button 리렌더링!");
return <button onClick={() => setCount((prev) => prev + 1)}>+</button>;
};
const App = () => (
<CountProvider>
<Display />
<Button />
</CountProvider>
);
export default App;
-> 문제점
setCount
가 호출되면 CountContext.Provider
의 value
가 변경됨 → 모든 하위 컴포넌트가 리렌더링됨Display
, Button
둘 다 리렌더링되지만, 사실 Button
은 count
와 관련 없는데도 리렌더링됨 import { create } from "zustand";
const useStore = create((set) => ({
count: 0,
increase: () => set((state) => ({ count: state.count + 1 })),
}));
const Display = () => {
const count = useStore((state) => state.count); // count만 구독
console.log("Display 리렌더링!");
return <h1>Count: {count}</h1>;
};
const Button = () => {
const increase = useStore((state) => state.increase); // increase만 구독
console.log("Button 리렌더링!");
return <button onClick={increase}>+</button>;
};
const App = () => (
<>
<Display />
<Button />
</>
);
export default App;
Display
는 count
만 구독 → count
가 변경될 때만 리렌더링
Button
은 increase
만 구독 → increase
함수는 변경되지 않으므로 리렌더링 없음
Context API처럼 모든 하위 컴포넌트가 리렌더링되는 문제를 방지
1) shallow비교를 사용해 불필요한 리렌더링 방지
import { shallow } from "zustand/shallow";
const { count, increase } = useStore(
(state) => ({ count: state.count, increase: state.increase }),
shallow
);
2) subscribe로 특정 상태 변경 감지 가능
useStore.subscribe((state) => {
console.log("count가 변경됨:", state.count);
});
3) persist미들웨어로 상태 유지 가능
import { create } from "zustand";
import { persist } from "zustand/middleware";
const useStore = create(
persist(
(set) => ({
count: 0,
increase: () => set((state) => ({ count: state.count + 1 })),
}),
{ name: "counter-storage" }
)
4) Context API없이 전역상태 사용 가능
-> Zustand는 Context API보다 불필요한 리렌더링을 방지하고, 코드가 더 간결하여 성능과 유지보수 측면에서 더 효율적이다.