본문 바로가기
JavaScript/React

Zustand vs Context API

by 비븽 2025. 6. 30.
항목 Zustand Context API
종류 외부 상태 관리 라이브러리 React 내장 기능
목적 전역 상태 간단하고 효율적으로 관리 전역 상태 전달 목적 (주입)
상태 업데이트 구독 기반 (Selective rendering) 모든 하위 컴포넌트가 리렌더링
복잡도 간단한 문법, 빠른 설정 Provider/Consumer 구조 필요
의존성 있음 (zustand 설치 필요) 없음 (React 내장)

 

구독 기반?

 

📌 Context API

// CounterContext.tsx
const CounterContext = createContext(null)

const CounterProvider = ({ children }) => {
  const [count, setCount] = useState(0)
  const increase = () => setCount((c) => c + 1)
  return (
    <CounterContext.Provider value={{ count, increase }}>
      {children}
    </CounterContext.Provider>
  )
}
// App.tsx
const Counter = () => {
  const { count, increase } = useContext(CounterContext)
  return <button onClick={increase}>{count}</button>
}

💡 특징: count나 increase 둘 중 하나만 필요해도, 둘 다 리렌더링

상태 기반이라 상태값이 바뀌면 참조하고 있는 모든 컴포넌트가 싹 랜더됨. 누가 사용하는지 정확히 따지지않고 그냥 다.

 

📌 Zustand

// store.ts
import { create } from 'zustand'

const useStore = create((set) => ({
  count: 0,
  increase: () => set((state) => ({ count: state.count + 1 })),
}))
// App.tsx
const Counter = () => {
  const count = useStore((state) => state.count)
  const increase = useStore((state) => state.increase)
  return <button onClick={increase}>{count}</button>
}

💡 특징: useStore((state) => state.count)처럼 필요한 값만 구독해서 불필요한 렌더링을 방지

구독 기반이라 상태를 사용하는 컴포넌트가 "내가 씀!"하고 명시적으로 구독?함. 그래서 진짜로 쓰고잇는 걔만 리랜더함

 

 

좀 더 간단한 예시

const CountContext = createContext({ count: 0 })

const Counter = () => { 
  const { count } = useContext(CountContext)
  return <div>{count}</div>
}
const useStore = create((set) => ({
  count: 0,
  text: "hello",
}))


const Counter = () => {// text가 바뀌어도 랜더안됨
  const count = useStore((state) => state.count) // count만 구독했기때문
  return <div>{count}</div> 
}

 

 

예제 시나리오

 

  • count와 text라는 두 상태가 있음
  • CountComponent: count만 사용
  • TextComponent: text만 사용
  • 상태가 바뀔 때 각 컴포넌트가 리렌더되는지 콘솔로 확인
// App.tsx
import React, { createContext, useContext, useState } from "react";

const StateContext = createContext(null);

const Provider = ({ children }) => {
  const [count, setCount] = useState(0);
  const [text, setText] = useState("hello");

  return (
    <StateContext.Provider value={{ count, setCount, text, setText }}>
      {children}
    </StateContext.Provider>
  );
};

const CountComponent = () => {
  const { count } = useContext(StateContext);
  console.log("🟠 CountComponent rendered");
  return <div>Count: {count}</div>;
};

const TextComponent = () => {
  const { text } = useContext(StateContext);
  console.log("🔵 TextComponent rendered");
  return <div>Text: {text}</div>;
};

export default function App() {
  return (
    <Provider>
      <Buttons />
      <CountComponent />
      <TextComponent />
    </Provider>
  );
}

const Buttons = () => {
  const { setCount, setText } = useContext(StateContext);
  return (
    <>
      <button onClick={() => setCount((c) => c + 1)}>+1</button>
      <button onClick={() => setText("updated!")}>Change Text</button>
    </>
  );
};

 

count만 바꿔도 TextComponent까지 같이 렌더링됨 

 

// store.ts
import { create } from "zustand";

export const useStore = create((set) => ({
  count: 0,
  text: "hello",
  setCount: () => set((state) => ({ count: state.count + 1 })),
  setText: () => set(() => ({ text: "updated!" })),
}));
// App.tsx
import React from "react";
import { useStore } from "./store";

const CountComponent = () => {
  const count = useStore((state) => state.count);
  console.log("🟠 CountComponent rendered");
  return <div>Count: {count}</div>;
};

const TextComponent = () => {
  const text = useStore((state) => state.text);
  console.log("🔵 TextComponent rendered");
  return <div>Text: {text}</div>;
};

const Buttons = () => {
  const setCount = useStore((state) => state.setCount);
  const setText = useStore((state) => state.setText);

  return (
    <>
      <button onClick={setCount}>+1</button>
      <button onClick={setText}>Change Text</button>
    </>
  );
};

export default function App() {
  return (
    <div>
      <Buttons />
      <CountComponent />
      <TextComponent />
    </div>
  );
}

 

  • setCount() → CountComponent만 렌더
  • setText() → TextComponent만 렌더

 

'JavaScript > React' 카테고리의 다른 글

d  (0) 2024.03.19
[React] 라이브러리 없이 자동 슬라이드 구현  (0) 2024.01.10
[React] input type date 아이콘 커스텀  (0) 2023.12.27
[React] 자동 무한 롤링 슬라이드 구현  (0) 2023.12.25
[React] 로딩바 구현  (0) 2023.12.18