전역 상태 관리는 리액트 개발에서 필수적인 요소입니다. React는 Context API를 통해 기본적인 전역 상태 관리 기능을 제공하지만, 이것만으로 충분하지 않은 경우가 많습니다.
예를 들어, 복잡한 애플리케이션에서 Context API
를 사용하면 코드가 복잡해지고 성능 저하
가 발생할 수 있습니다.
따라서, 바로 이러한 문제를 해결하기 위해 등장한 것이 Zustand
와 같은 전역 상태 관리 라이브러리입니다.
import React, { createContext, useContext, useState } from 'react';
const CounterContext = createContext();
export const CounterProvider = ({ children }) => {
const [count, setCount] = useState(0);
const increase = () => {
console.log("Context API: 증가 함수 호출됨");
setCount((prev) => prev + 1);
};
return (
<CounterContext.Provider value={{ count, increase }}>
{children}
</CounterContext.Provider>
);
};
export const useCounter = () => {
console.log("Context API: useCounter 호출됨");
return useContext(CounterContext);
};
import React from 'react';
import { CounterProvider, useCounter } from './CounterContext';
function Counter() {
const { count, increase } = useCounter();
console.log("Context API: Counter 컴포넌트 렌더링됨");
return (
<div>
<p>Count: {count}</p>
<button onClick={increase}>증가</button>
</div>
);
}
export default function App() {
return (
<CounterProvider>
<Counter />
</CounterProvider>
);
}
Context API: useCounter 호출됨
Context API: Counter 컴포넌트 렌더링됨
Context API: 증가 함수 호출됨
Context API: useCounter 호출됨
Context API: Counter 컴포넌트 렌더링됨
Context API는 전역 상태를 관리하기 위한 기본적인 도구지만, Provider의 값이 변경되면 하위의 모든 컴포넌트가 리렌더링된다는 단점이 있습니다. 이로 인해 위와 같이 상태가 1씩 증가할 때마다 useCounter와 Counter 컴포넌트가 반복적으로 호출되고 렌더링됩니다.
리렌더링 최적화가 어렵고 불필요한 연산이 많아지기
때문에, 이런 문제를 해결하기 위해 Zustand
와 같은 전역 상태 관리 라이브러리가 등장하게 되었습니다.
import { create } from 'zustand';
const useStore = create((set) => ({
count: 0,
increase: () => {
console.log("Zustand: 증가 함수 호출됨");
set((state) => ({ count: state.count + 1 }));
},
}));
export default useStore;
import React from 'react';
import useStore from './store';
function Counter() {
const { count, increase } = useStore();
console.log("Zustand: Counter 컴포넌트 렌더링됨");
return (
<div>
<p>Count: {count}</p>
<button onClick={increase}>증가</button>
</div>
);
}
export default function App() {
return <Counter />;
}
- create 함수로 상태와 업데이트 로직을 정의
- 컴포넌트는 useStore 훅을 사용하여 필요한 상태를 구독
- 상태가 변경되면 구독된 컴포넌트만 리렌더링
Zustand: Counter 컴포넌트 렌더링됨
Zustand: 증가 함수 호출됨
Zustand: Counter 컴포넌트 렌더링됨
Zustand: 증가 함수 호출됨
Zustand: Counter 컴포넌트 렌더링됨
Zustand: 증가 함수 호출됨
Zustand: Counter 컴포넌트 렌더링됨
비교 항목 | Context API | Zustand |
---|---|---|
코드 복잡도 | Provider와 useContext 필요 | 단순한 useStore 사용 |
리렌더링 성능 | 모든 하위 컴포넌트 리렌더링 | 구독된 컴포넌트만 리렌더링 |
사용성 | React 내부에서만 사용 가능 | React 외부에서도 사용 가능 |
Context API는 기본적인 전역 상태 관리에 적합하지만, 리렌더링 최적화와 코드 간결성 측면에서 한계가 있습니다.
반면, Zustand는 리렌더링을 최소화하고, 간결한 코드 구조와 유연성을 제공하여 대규모 애플리케이션에서도 효과적으로 상태를 관리할 수 있는 강력한 도구입니다.