| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 장고 가상환경
- 파이썬 제어문
- 넥스트js
- Python
- 자바 기본타입
- django virtualenv
- 파이썬 반복문
- 도전
- 파이썬
- 다중조건문
- Kotlin 클래스
- 강제 타입변환
- python Django
- Python Class
- 희망
- 파이썬 장고
- 성공
- Kotlin 조건문
- Kotlin Class
- Kotlin 클래스 속성정의
- activate 오류
- 클래스 속성
- git
- 파이썬 클래스
- Kotlin If
- Variable declaration
- github
- 좋은글
- NextJs
- Kotlin else if
Archives
- Today
- Total
키모스토리
Zustand 본문
반응형
1. Zustand란?
Zustand는 React에서 전역 상태를 매우 간단하게 관리할 수 있는 라이브러리입니다.
특징
- Redux처럼 복잡한 보일러플레이트가 거의 없습니다.
- Context Provider를 필수로 만들지 않아도 됩니다(대부분의 경우).
- Store가 작고 가벼우며, 필요한 컴포넌트만 선택적으로 구독할 수 있습니다.
- 전역 상태를 “훅 형태”로 바로 불러다 쓰는 방식이 직관적입니다.
2. 설치 방법
아래 중 프로젝트에서 사용하는 패키지 매니저로 설치하시면 됩니다.
pnpm
pnpm add zustand
npm
npm i zustand
yarn
yarn add zustand
3. Zustand 기본 개념
Zustand는 크게 2가지만 이해하시면 됩니다.
- Store 생성: create()로 전역 상태와 액션(변경 함수)을 정의합니다.
- 구독(사용): 컴포넌트에서 useStore((state) => state.무엇) 형태로 필요한 값만 가져옵니다.
4. 예제: 사용자 정보(user)를 전역 상태로 관리하기
목표는 다음과 같습니다.
- 전역 상태: user = { email, name }
- 액션: setEmail, setName, setUser, reset
4-1) Store 파일 생성
예시 경로: /lib/stores/user.store.ts
"use client";
import { create } from "zustand";
export type User = {
email: string;
name: string;
};
type UserStore = {
user: User;
setEmail: (email: string) => void;
setName: (name: string) => void;
setUser: (user: User) => void;
reset: () => void;
};
const initialUser: User = { email: "", name: "" };
export const useUserStore = create<UserStore>((set) => ({
user: initialUser,
// email만 변경
setEmail: (email) =>
set((state) => ({ user: { ...state.user, email } })),
// name만 변경
setName: (name) =>
set((state) => ({ user: { ...state.user, name } })),
// user 통째로 교체
setUser: (user) => set({ user }),
// 초기화
reset: () => set({ user: initialUser }),
}));
5. Store 사용법(기본 패턴)
5-1) 값 조회(읽기)
const user = useUserStore((s) => s.user);
5-2) 필요한 값만 선택 조회(권장)
const email = useUserStore((s) => s.user.email);
const name = useUserStore((s) => s.user.name);
이 방식이 좋은 이유는, 컴포넌트가 “정말 필요한 값”이 바뀔 때만 리렌더되기 때문입니다.
5-3) 액션(변경 함수) 가져오기
const setEmail = useUserStore((s) => s.setEmail);
const reset = useUserStore((s) => s.reset);
6. 실제 페이지 예제: 입력 폼에서 전역 상태 업데이트
/app/users/update/page.tsx
"use client";
import { useRouter } from "next/navigation";
import { useUserStore } from "@/lib/stores/user.store";
export default function UsersUpdatePage() {
const router = useRouter();
const user = useUserStore((s) => s.user);
const setEmail = useUserStore((s) => s.setEmail);
const setName = useUserStore((s) => s.setName);
return (
<main className="mx-auto max-w-xl p-6">
<div className="rounded-2xl border bg-white p-6 shadow-sm">
<h1 className="text-xl font-semibold">Users Update Page</h1>
<div className="mt-6 space-y-3">
<input
type="email"
value={user.email}
placeholder="Enter your Email"
onChange={(e) => setEmail(e.target.value)}
className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm
focus:border-gray-400 focus:ring-4 focus:ring-gray-100 outline-none"
/>
<input
type="text"
value={user.name}
placeholder="Enter your Name"
onChange={(e) => setName(e.target.value)}
className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm
focus:border-gray-400 focus:ring-4 focus:ring-gray-100 outline-none"
/>
<div className="flex gap-2 pt-2">
<button
type="button"
onClick={() => router.push("/users/updated-user")}
className="rounded-lg border border-gray-300 bg-white px-4 py-2 text-sm
hover:bg-gray-50 active:bg-gray-100"
>
Update
</button>
<button
type="button"
onClick={() => useUserStore.getState().reset()}
className="rounded-lg border border-gray-300 bg-white px-4 py-2 text-sm
hover:bg-gray-50 active:bg-gray-100"
>
Reset
</button>
</div>
</div>
</div>
</main>
);
}
포인트
- Update 버튼에서 router.push("/users/updated-user")로 이동하면 같은 탭에서 클라이언트 네비게이션이 일어나므로 전역 상태가 유지됩니다.
- Reset은 useUserStore.getState().reset()처럼 “이벤트 시점에 한 번 호출”하는 패턴도 가능합니다.
7. 전역 상태 확인 페이지 예제
/app/users/updated-user/page.tsx
"use client";
import { useUserStore } from "@/lib/stores/user.store";
export default function UpdatedUserPage() {
const user = useUserStore((s) => s.user);
return (
<main className="mx-auto max-w-xl p-6">
<div className="rounded-2xl border bg-white p-6 shadow-sm">
<h1 className="text-xl font-semibold">Updated User Page</h1>
<div className="mt-4 space-y-2 text-sm">
<div>
<span className="font-medium">User Name :</span> {user.name}
</div>
<div>
<span className="font-medium">User Email :</span> {user.email}
</div>
</div>
</div>
</main>
);
}
8. (선택) 새로고침해도 상태를 유지하고 싶을 때(persist)
Zustand 기본 store는 브라우저 메모리에만 존재합니다.
즉, 새로고침(Full Reload)을 하면 초기화됩니다.
만약 새로고침에도 유지하고 싶다면 persist 미들웨어를 사용합니다.
"use client";
import { create } from "zustand";
import { persist, createJSONStorage } from "zustand/middleware";
export type User = { email: string; name: string };
type UserStore = {
user: User;
setEmail: (email: string) => void;
setName: (name: string) => void;
reset: () => void;
};
const initialUser: User = { email: "", name: "" };
export const useUserStore = create<UserStore>()(
persist(
(set) => ({
user: initialUser,
setEmail: (email) => set((s) => ({ user: { ...s.user, email } })),
setName: (name) => set((s) => ({ user: { ...s.user, name } })),
reset: () => set({ user: initialUser }),
}),
{
name: "user-store",
storage: createJSONStorage(() => localStorage),
}
)
);
9. 마무리 정리
- Zustand는 설치와 사용이 간단하고, Next.js App Router에서도 부담 없이 적용할 수 있습니다.
- 전역 상태는 create()로 만들고, 페이지/컴포넌트에서는 useUserStore(selector)로 필요한 값만 가져오면 됩니다.
- 페이지 이동 시 상태가 유지되려면 Next.js의 클라이언트 네비게이션(Link/router.push) 흐름을 사용해야 하며,
- 새로고침에도 유지하려면 persist를 적용하면 됩니다.
반응형
'Web Devlopment > NextJs' 카테고리의 다른 글
| TanStack Query (react-query) - #2 (useMutation, 등록/수정/삭제) (0) | 2026.01.18 |
|---|---|
| TanStack Query (react-query) - #1 (useQuery, 조회) (0) | 2026.01.18 |
| Next.js Server Actions: <form action>로 CRUD 만들기 (메모리 DB 예시) (0) | 2026.01.17 |
| #37. Next.js 16 + Prisma 7 + SQLite 회원관리 예제 (0) | 2026.01.02 |
| #36. form action(Server Actions) vs onSubmit(Client Handler) (0) | 2026.01.01 |
