부모에서 아주 깊은 곳에 있는 자식 컴포넌트로 데이터를 전달하려면, 중간에 있는 컴포넌트들은 데이터를 쓰지도 않으면서 오직 전달만을 위해 Props를 받아 넘겨야 합니다. 이를 Props Drilling(프롭스 내리꽂기)이라고 합니다.
Context API는 이러한 문제를 해결하는 리액트 내장 전역 상태 관리 도구입니다. 최상위에서 Provider로 감싸고 값을 공급하면, 하위의 어떤 컴포넌트든 깊이와 상관없이 useContext 훅을 이용해 해당 값을 바로 꺼내 쓸 수 있습니다.
Props Drilling vs Context API
언제 Context API를 써야 할까?
Context API는 만능 전역 상태 관리 도구가 아닙니다. 'Props Drilling을 우회하여 값을 전달하는 통로'에 가깝습니다. 상태가 자주 변경되는 경우 하위 컴포넌트 전체가 리렌더링 될 수 있으므로, 테마(Dark/Light), 로그인 유저 정보, 다국어 설정 등 변경이 잦지 않은 전역 데이터에 사용하는 것이 적합합니다.
import React, { useState } from 'react';
import { ThemeContext } from './ThemeContext';
import MiddleComponent from './MiddleComponent';
// 4. 최상위 부모 컴포넌트
export default function App() {
const [theme, setTheme] = useState('light');
const toggleTheme = () => setTheme(prev => prev === 'light' ? 'dark' : 'light');
return (
// Provider의 value 속성으로 공유할 데이터와 함수를 전달합니다.
<ThemeContext.Provider value={{ theme, toggleTheme }}>
<div style={{ padding: '20px', background: '#f8fafc', borderRadius: '8px' }}>
<h3 style={{ marginTop: 0 }}>Context API 예제</h3>
<MiddleComponent />
</div>
</ThemeContext.Provider>
);
}
🔒 localhost:8000/preview
Redux의 시대는 가고, Zustand의 시대가 왔다
Context API는 전역 상태가 바뀔 때마다 하위 컴포넌트가 전부 리렌더링되는 성능 이슈가 있어, 단순한 테마 변경 정도에만 적합합니다. 그래서 과거에는 무겁고 복잡한 Redux를 사용했습니다.
독일어로 '상태'를 뜻하는 Zustand(쥬스탠드)는 Redux의 단점(방대한 보일러플레이트 코드, 복잡한 설정)을 모두 없앤 초경량 상태 관리 라이브러리입니다. Provider로 앱을 감쌀 필요도 없고, 훅을 생성하여 어디서든 직관적으로 상태와 함수를 꺼내 쓸 수 있습니다.
Zustand의 전역 상태 구조
Zustand 스토어는 리액트 컴포넌트 트리 바깥에 완전히 독립적으로 존재합니다. 따라서 <Provider>로 앱을 감쌀 필요가 없으며, 깊숙한 곳에 있는 컴포넌트라도 훅(Hook)을 통해 스토어에 직접 연결(Subscribe)되어 최상의 렌더링 성능을 보장합니다.
bash - Terminal
npm install zustand
핵심 API: create, set, get, 그리고 state
Zustand를 다루기 위해 반드시 알아야 하는 4가지 핵심 개념입니다. 스토어를 정의할 때 이들이 어떻게 동작하는지 이해하는 것이 가장 중요합니다.
개념/메서드
역할 및 설명
create
Zustand 스토어를 생성하는 가장 기본적인 함수입니다. 이 함수 안에 상태(데이터)와 액션(상태를 변경하는 함수)을 정의한 객체를 반환하는 콜백 함수를 넣습니다. 반환된 훅(Hook)을 컴포넌트에서 호출하여 사용합니다.
set
상태를 업데이트(변경)하는 함수입니다. 기존 상태를 복사할 필요 없이, 변경할 부분만 객체로 넘겨주면 Zustand가 알아서 기존 상태와 얕은 병합(Shallow Merge)을 수행하여 업데이트합니다.
get
현재 스토어의 전체 상태값을 조회하는 함수입니다. 스토어 내부의 어떤 액션 함수에서, 다른 상태값을 읽어와서 로직에 활용해야 할 때 유용하게 사용됩니다.
state
스토어에 저장되어 있는 상태 객체 그 자체입니다. 주로 set((state) => ({ count: state.count + 1 })) 처럼 상태를 업데이트할 때, 이전 상태값을 참조하기 위한 매개변수로 콜백에 전달됩니다.
위 명령어로 Zustand를 설치한 뒤, 아래와 같이 스토어를 생성하고 컴포넌트에서 활용할 수 있습니다.
import BearCounter from './BearCounter';
import Controls from './Controls';
export default function App() {
// Provider 태그가 아예 필요 없습니다!
return (
<div style={{ padding: '20px', background: '#f8fafc', borderRadius: '8px' }}>
<BearCounter />
<Controls />
</div>
);
}