Project-hongsta(3)

강홍규(カンホンギュ)·2026년 1월 21일

Project

목록 보기
3/9
post-thumbnail

Zustand - 全域状態管理(ぜんいきじょうたいかんり)ライブラリ

🌐 全域状態(ぜんいきじょうたい)とは?

概念(がいねん)

グローバルなstate値(あたい)を新(あたら)しく生成(せいせい)、修正(しゅうせい)できるように管理(かんり)することです。
ユーザー認証情報(にんしょうじょうほう)、テーマ情報(じょうほう)、カート情報(じょうほう)などを管理(かんり)します。

글로벌한 state 값을 새롭게 생성, 수정할 수 있도록 관리하는 것입니다.
사용자 인증 정보, 테마 정보, 장바구니 정보 등을 관리합니다.

Props Drillingの問題(もんだい)

propsを使(つか)って一段階(いちだんかい)ずつ下(した)に渡(わた)すと、Props Drilling問題(もんだい)が発生(はっせい)します。
この問題(もんだい)を解決(かいけつ)するためにContext API、Redux、Zustandなどがあります。

props를 사용해서 한 단계씩 아래로 전달하면 Props Drilling 문제가 발생합니다.
이 문제를 해결하기 위해 Context API, Redux, Zustand 등이 있습니다.

// Props Drilling 예시
<App>
  <Parent user={user}>
    <Child user={user}>
      <GrandChild user={user}>
        {/* 3단계를 거쳐 전달 */}
      </GrandChild>
    </Child>
  </Parent>
</App>
状態管理(じょうたいかんり)ツール特徴(とくちょう)단점
Context APIReact 내장(ないぞう)Provider 리렌더링 시 모든 하위 컴포넌트 리렌더링
Redux강력(きょうりょく)한 기능(きのう)복잡한 설정
Zustand가볍고 직관적(ちょっかんてき)-

Context API 한계: Provider가 리렌더링될 때마다 모든 하위 컴포넌트가 리렌더링 → 극소적인 데이터 공유에만 적합


🎯 なぜZustandなのか?

Zustandの長所(ちょうしょ)

多(おお)くの人(ひと)が使(つか)っており、容量(ようりょう)が非常(ひじょう)に軽(かる)く、直観的(ちょっかんてき)で学(まな)びやすいです。
TypeScriptとの統合(とうごう)も簡単(かんたん)で、ボイラープレートコードが少(すく)ないです。

많은 사람이 사용하고 있으며, 용량이 매우 가볍고, 직관적이어서 배우기 쉽습니다.
TypeScript와의 통합도 쉽고 보일러플레이트 코드가 적습니다.

npm i zustand

📖 Zustand 基本使用法(きほんしようほう)

ストア作成(さくせい)

store/count.ts

import { create } from "zustand"; // store을 생성할 수 있음

type Store = {
  count: number;
  increase: () => void;
  decrease: () => void;
};

export const useCountStore = create<Store>((set, get) => ({
  count: 0,
  increase: () => {
    set((store) => ({ count: store.count + 1 }));
  },
  decrease: () => {
    set((store) => ({ count: store.count - 1 }));
  },
}));
要素(ようそ)役割(やくわり)설명
createストア生成(せいせい)전역 상태 저장소 생성
set状態(じょうたい)更新(こうしん)상태 업데이트 함수
get状態(じょうたい)取得(しゅとく)현재 상태 가져오기

コンポーネントで使用(しよう)

pages/counter-page.tsx

import { Button } from "@/components/ui/button";
import { useCountStore } from "@/store/count";

export default function CounterPage() {
  const store = useCountStore();
  const { count, increase, decrease } = store;

  return (
    <div>
      <h1 className="text-2xl font-bold">Counter</h1>
      <div>{count}</div>
      <div>
        <Button onClick={decrease}>-</Button>
        <Button onClick={increase}>+</Button>
      </div>
    </div>
  );
}

객체 구조 분해: const { count, increase, decrease } = store;로 필요한 값만 추출


🔧 最適化(さいてきか) - Selector使用(しよう)

リレンダリング問題(もんだい)

一(ひと)つのコンポーネントでストア全体(ぜんたい)を使(つか)うと、不要(ふよう)なリレンダリングが発生(はっせい)します。
Selector関数(かんすう)を使(つか)って必要(ひつよう)な値(あたい)だけを選択(せんたく)します。

하나의 컴포넌트에서 스토어 전체를 사용하면 불필요한 리렌더링이 발생합니다.
Selector 함수를 사용해서 필요한 값만 선택합니다.

コンポーネント分離(ぶんり)

pages/counter-page.tsx

import Controller from "@/components/counter/controller";
import Viewer from "@/components/counter/viewer";

export default function CounterPage() {
  return (
    <div>
      <h1 className="text-2xl font-bold">Counter</h1>
      <Viewer />
      <Controller />
    </div>
  );
}

components/counter/viewer.tsx

import { useCount } from "@/store/count";

export default function Viewer() {
  const count = useCount();

  return <div>{count}</div>;
}

components/counter/controller.tsx

import { Button } from "@/components/ui/button";
import { useDecreaseCount, useIncreaseCount } from "@/store/count";

export default function Controller() {
  const increase = useIncreaseCount();
  const decrease = useDecreaseCount();

  return (
    <div>
      <Button onClick={increase}>-</Button>
      <Button onClick={decrease}>+</Button>
    </div>
  );
}

개발자 도구 팁: React DevTools → Components → "Highlight updates when components render" 체크하면 리렌더링 확인 가능

カスタムフック作成(さくせい)

store/count.ts

import { create } from "zustand";

type Store = {
  count: number;
  actions: {
    increaseOne: () => void;
    decreaseOne: () => void;
  };
};

export const useCountStore = create<Store>((set, get) => ({
  count: 0,
  actions: {
    increaseOne: () => {
      set((store) => ({
        count: store.count + 1,
      }));
    },
    decreaseOne: () => {
      set((store) => ({
        count: store.count - 1,
      }));
    },
  },
}));

// 커스텀 훅
export const useCount = () => {
  const count = useCountStore((store) => store.count);
  return count;
};

export const useIncreaseCount = () => {
  const increase = useCountStore((store) => store.actions.increaseOne);
  return increase;
};

export const useDecreaseCount = () => {
  const decrease = useCountStore((store) => store.actions.decreaseOne);
  return decrease;
};
パターンリレンダリング설명
useCountStore()전체(ぜんたい)모든 값 변경 시 리렌더링
useCountStore((s) => s.count)count만count 변경 시만 리렌더링
カスタムフック선택적(せんたくてき)안정적이고 재사용 가능

Selector 콜백: 원하는 값만 선택하여 불필요한 리렌더링 방지


🛠️ Zustand ミドルウェア

ミドルウェアとは?

特定(とくてい)のロジックに中間(ちゅうかん)処理(しょり)を追加(ついか)する道具(どうぐ)です。
ログ出力(しゅつりょく)、重複(じゅうふく)確認(かくにん)などができます。

특정 로직에 중간 처리를 추가하는 도구입니다.
로그 출력, 중복 확인 등을 할 수 있습니다.

combine ミドルウェア

stateとactionを分離(ぶんり)して型(かた)推論(すいろん)を簡単(かんたん)にします。
自動(じどう)で型(かた)を推論(すいろん)してくれます。

state와 action을 분리해서 타입 추론을 쉽게 합니다.
자동으로 타입을 추론해줍니다.

import { create } from "zustand";
import { combine } from "zustand/middleware";

export const useCountStore = create(
  combine({ count: 0 }, (set, get) => ({
    actions: {
      increaseOne: () => {
        set((state) => ({ count: state.count + 1 }));
      },
      decreaseOne: () => {
        set((state) => ({ count: state.count - 1 }));
      },
    },
  })),
);

combine 장점: state는 state끼리, action은 action끼리 묶어서 관리 → 자동 타입 추론

immer ミドルウェア

不変性(ふへんせい)を自動(じどう)で管理(かんり)してくれます。
複雑(ふくざつ)な状態(じょうたい)更新(こうしん)を簡単(かんたん)に作成(さくせい)できます。

불변성을 자동으로 관리해줍니다.
복잡한 상태 업데이트를 쉽게 작성할 수 있습니다.

npm i immer
import { create } from "zustand";
import { combine } from "zustand/middleware";
import { immer } from "zustand/middleware/immer";

export const useCountStore = create(
  immer(
    combine({ count: 0 }, (set, get) => ({
      actions: {
        increaseOne: () => {
          set((state) => {
            state.count += 1; // 불변성 관리 불필요!
          });
        },
        decreaseOne: () => {
          set((state) => {
            state.count -= 1;
          });
        },
      },
    })),
  ),
);

export const useCount = () => {
  const count = useCountStore((store) => store.count);
  return count;
};

export const useIncreaseCount = () => {
  const increase = useCountStore((store) => store.actions.increaseOne);
  return increase;
};

export const useDecreaseCount = () => {
  const decrease = useCountStore((store) => store.actions.decreaseOne);
  return decrease;
};

主要(しゅよう)ミドルウェア一覧(いちらん)

ミドルウェア機能(きのう)설명
combinestate/action 分離(ぶんり)타입 추론 자동화
immer不変性(ふへんせい)管理(かんり)직접 값 수정 가능
devtoolsデバッグRedux DevTools 연동
persist永続化(えいぞくか)localStorage 저장
subscribeWithSelector選択的(せんたくてき)구독(こうどく)특정 값만 감시

📋 まとめ

Zustandは軽量(けいりょう)で直観的(ちょっかんてき)な全域状態管理(ぜんいきじょうたいかんり)ライブラリです。
Selectorとミドルウェアで最適化(さいてきか)された状態管理(じょうたいかんり)ができます。

Zustand는 가볍고 직관적인 전역 상태 관리 라이브러리입니다.
Selector와 미들웨어로 최적화된 상태 관리를 할 수 있습니다.

핵심: 기본 스토어 생성 → 커스텀 훅으로 Selector 구현 → combine + immer로 편리한 상태 관리

profile
日本での就職を目指している26歳の韓国人開発者です。 アプリとweb開発、両方準備中で、日本語で技術概念を整理しながら日本語も一緒に勉強する予定です。 コツコツ続けるのが好きな開発者の成長記録を、一緒に見守っていただけると嬉しいです! 일본에서의 취업을 목표로 하고 있는 26살의 한국인 개발자입니다. 앱과 웹 개발, 둘 다 준비 중이며, 일본어로 기술 개념을 정리하면서 일본어도 함께 공부할 예정입니다. 꾸준히 계속하는 것을 좋아하는 개발자의 성장 기록을, 함께 지켜봐

0개의 댓글