Context API와 Zustand 예시 코드를 보기만 해도 Zustand를 사용하는 이유를 알 수 있다.
// Context API 보일러플레이트 예시
import React, { createContext, useContext, useState } from 'react';
const CounterContext = createContext();
export const CounterProvider = ({ children }) => {
const [count, setCount] = useState(0);
return (
<CounterContext.Provider value={{ count, setCount }}>
{children}
</CounterContext.Provider>
);
};
export const useCounter = () => {
const context = useContext(CounterContext);
if (!context) {
throw new Error('useCounter must be used within a CounterProvider');
}
return context;
};
// Context API 사용 예시
import React from 'react';
import { CounterProvider, useCounter } from './CounterContext';
const CounterComponent = () => {
const { count, setCount } = useCounter();
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
<button onClick={() => setCount(count - 1)}>Decrement</button>
</div>
);
};
export const App = () => (
<CounterProvider>
<CounterComponent />
</CounterProvider>
);
// Zustand 보일러플레이트 예시
import create from 'zustand';
const useCounterStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
}));
// Zustand 사용 예시
import React from 'react';
import useCounterStore from './counterStore';
const CounterComponent = () => {
const { count, increment, decrement } = useCounterStore();
return (
<div>
<p>{count}</p>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
};
export const App = () => <CounterComponent />;
사용이 간편하고 초기 세팅(보일러플레이트) 코드가 비교적 적다.
위 예시 코드를 보면 확실히 Zustand의 코드가 적고 손쉽게 작성할 수 있다.
Context API와 달리 Provider를 사용하지 않아 Provider hell 문제를 해결할 수 있다.
Context API를 사용하다보면 Provider를 감싸야 하는데 Zustand는 Provider 없이 커스텀 훅처럼 사용할 수 있다.
Context API는 Provider에 의존하는 모든 컴포넌트를 재렌더링하지만, Zustand의 셀렉터 함수를 활용하면 재렌더링을 쉽게 방지하여 관련된 컴포넌트만 재렌더링을 시킬 수 있다.
store 안에 필요한 상태만 선택하여 불필요한 재렌더링을 손쉽게 피할 수 있다.
간단하게 persist 미들웨어를 활용하여 로컬스토리지와 손쉽게 동기화하여 사용할 수 있다.