문제점 (Prop Drilling): 앱의 깊숙한 곳에 있는 컴포넌트에 상태를 전달하기 위해, 중간에 있는 수많은 컴포넌트를 거쳐 Props를 계속해서 전달해야 하는 문제. 코드의 가독성과 유지보수성을 크게 저하시킵니다.
해결책 (Context API): React에 내장된 기능으로, 컴포넌트 트리에 전역적인 데이터 터널을 만들어 Props 전달 없이도 하위 컴포넌트가 데이터에 직접 접근할 수 있게 합니다.
createContext: 전역적으로 공유할 데이터의 Context 객체를 생성합니다.Provider: 생성한 Context 객체에 포함된 Provider 컴포넌트로 앱의 일부를 감쌉니다. value prop을 통해 하위 컴포넌트에 전달할 실제 데이터(상태, 함수 등)를 지정합니다.useContext: Provider 하위에 있는 어떤 컴포넌트에서든 useContext Hook을 사용하여 value로 전달된 데이터에 직접 접근(소비)합니다.props가 변경되지 않은 자식에게는 불필요한 연산이므로, 성능 저하의 원인이 될 수 있습니다.React.memo:
props가 변경되었을 때만 해당 컴포넌트를 리렌더링하도록 만듭니다.props와 현재 props를 얕게(shallowly) 비교하여 변경 여부를 판단합니다.useCallback:
memo로 감싼 자식에게 prop으로 전달하면, prop이 변경된 것으로 간주되어 memo가 무력화됩니다.useCallback은 함수 자체를 메모이제이션(memoization)하여, 의존성 배열([])의 값이 변경되지 않는 한 함수를 재생성하지 않고 재사용하게 해주는 Hook입니다.컴포넌트 분리:
Context API는 훌륭한 내장 기능이지만, Provider 설정이 번거롭고 특정 상황에서 불필요한 리렌더링을 유발할 수 있습니다. Zustand는 이러한 단점을 보완하는 간결한 전역 상태 관리 라이브러리입니다.최소한의 보일러플레이트: create 함수 하나로 상태(state)와 상태 변경 함수(action)를 포함하는 스토어(Store)를 생성할 수 있습니다.
Provider 불필요: 앱을 <Provider>로 감쌀 필요 없이, 어떤 컴포넌트에서든 스토어를 Hook처럼 호출하여 상태를 구독하고 사용할 수 있습니다.
persist 미들웨어: 단 몇 줄의 코드로 스토어의 상태를 localStorage에 자동으로 저장하고, 새로고침 시에도 상태를 유지하는 영속성을 쉽게 구현할 수 있습니다.
// store/authStore.js
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
const useAuthStore = create(
persist(
(set) => ({
isLoggedIn: false,
login: () => set({ isLoggedIn: true }),
}),
{ name: 'auth-storage' } // localStorage에 저장될 키
)
);
React.memo로 컴포넌트를, useCallback으로 함수를 메모이제이션할 수 있습니다.Context API보다 더 간결하고 직관적인 문법으로 전역 상태 관리를 가능하게 하며, persist 미들웨어를 통해 상태 영속성을 손쉽게 구현할 수 있는 강력한 라이브러리입니다.