[Next.js] Zustand의 개념 및 사용법을 알아보자
Next.js Zustand 개념 및 사용법을 알아보자!
Zustand는 정말 가벼운 상태 관리 라이브러리로, 정말 많은 기업에서 사용하고 있다. 사용법은 무엇인지 개념은 어떻게 되는지 알아보도록 하자!
Zustand 주요 장점
Zustand는 Hooks를 사용하여 편리한 API를 제공하며, 작고 빠르며 확장성이 좋다.
-
보일러플레이트의 최소화
- 반복적으로 사용해야하는 코드 양을 최소화하여 프로젝트의 유지보수를 쉽게 한다.
-
아주 작은 크기
- Zustand의 핵심 로직은 바닐라 자바스크립트 수십줄로 구성되어 있는 만큼, 매우 가벼운 라이브러리이다.
-
효율적인 렌더링
- 상태가 변경될 때만 컴포넌트를 렌더링하므로, 불필요한 리렌더링을 방지하여 성능을 향상 시킨다.
Zustand 사용법 (counter)
Next.js에서 간단한 카운터 앱을 만들어 보며 Zustand를 어떻게 사용하는지 알아보자
2-1) 설치 방법
아래의 명령어를 터미널에 입력한다.
## npm
npm install zustand
## yarn
yarn add zustand
2-2) counter store 생성
app/store 디렉토리에 스토어를 생성해준다.
// src/store/useCounterStore.ts
import { create } from 'zustand';
interface CounterStore {
count: number;
increment: () => void;
decrement: () => void;
}
const useCounterStore = create<CounterStore>((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
}));
export default useCounterStore;
2-3) Store 사용하기
useCounterStore에서 정의한 상태값과 함수를 import해서 사용한다.
"use client";
import counterStore from '../store/counterStore';
const CounterPage = () => {
const { count, increment, decrement } = useCounterStore();
return (
<div>
<h1>Counter: {count}</h1>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
};
export default CounterPage;
Zustand 사용법 (todo list)
Next.js에서 투두 리스트를 만들어보며 Zustand를 어떻게 사용하는지 알아보자
3-2) todo store 생성
app/store 디렉토리에 스토어를 생성해준다.
// src/store/todoStore.ts
import { create } from 'zustand';
interface Todo {
id: number;
text: string;
completed: boolean;
}
interface TodoStore {
todos: Todo[];
addTodo: (todo: Todo) => void;
removeTodo: (id: number) => void;
toggleTodo: (id: number) => void;
completeTodo: (id: number) => void;
}
const useTodoStore = create<TodoStore>((set) => ({
todos: [],
addTodo: (todo) => set((state) => ({
todos: [...state.todos, todo],
})),
removeTodo: (id) => set((state) => ({
todos: state.todos.filter((todo) => todo.id !== id),
})),
toggleTodo: (id) => set((state) => ({
todos: state.todos.map((todo) =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
),
})),
completeTodo: (id) => set((state) => ({
todos: state.todos.map((todo) =>
todo.id === id ? { ...todo, completed: true } : todo
),
})),
}));
export default useTodoStore;
3-3) TodoFrom.tsx
-
addTodo: addTodo(todo.id)를 호출하여 Todo를 완료로 표시한다.
// src/_components/TodoForm.tsx
"use client";
import { FC, useState } from 'react';
import useTodoStore from '../store/todoStore';
// FC: 함수형 컴포넌트 정의
const TodoForm: FC = () => {
const [text, setText] = useState('');
// Zustand 스토어에서 addTodo 가져옴
const addTodo = useTodoStore((state) => state.addTodo);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (text.trim()) {
const newTodo = { id: Date.now(), text, completed: false };
addTodo(newTodo);
setText('');
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={text}
onChange={(e) => setText(e.target.value)}
placeholder="할 일을 입력하세요"
/>
<button type="submit">추가</button>
</form>
);
};
export default TodoForm;
3-3) TodoList.tsx
-
toggleTodo: toggleTodo(todo.id)를 호출하여 Todo의 완료 상태를 토글한다. -
completeTodo: completeTodo(todo.id)를 호출하여 Todo를 완료로 표시한다. -
removeTodo: removeTodo(todo.id)를 호출하여 Todo를 삭제한다.
// src/_components/TodoList.tsx
"use client";
import { FC } from 'react';
import useTodoStore from '../store/todoStore';
const TodoList: FC = () => {
const { todos, removeTodo, toggleTodo, completeTodo } = useTodoStore();
return (
<ul>
{todos.map((todo) => (
<li key={todo.id}>
<span style=>
{todo.text}
</span>
<button onClick={() => toggleTodo(todo.id)}>Toggle</button>
<button onClick={() => completeTodo(todo.id)}>Complete</button>
<button onClick={() => removeTodo(todo.id)}>Remove</button>
</li>
))}
</ul>
);
};
export default TodoList;
마무리
이전에 React로 제작한 팀 프로젝트 - 가을축제핑에서 사용해보았는데, 기억이 잘 안났던 부분도 있고 Next.js에서는 어떻게 사용해보는지 알아보기위해 Counter, Todo 기능을 구현해보면서 다시 한번 문법이 간결하고 정말 편리하다고 느꼈다.