[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 기능을 구현해보면서 다시 한번 문법이 간결하고 정말 편리하다고 느꼈다.