Hello, lại là mình đây, hôm nay mình muốn chia sẻ với các bạn về một thư viện quản lý state mà mình đã trải nghiệm gần đây và thấy khá là ấn tượng, đó là Zustand. Nếu bạn đã từng đau đầu với Redux vì quá nhiều cấu hình phức tạp, hoặc cảm thấy Context API của React chưa đáp ứng đủ nhu cầu, thì Zustand có thể là giải pháp bạn đang tìm kiếm.
Trong bài viết này, mình sẽ hướng dẫn cách sử dụng Zustand trong dự án NextJS. Mình sẽ cố gắng giải thích từng phần cách dễ hiểu nhất, kèm theo các ví dụ với hy vọng các bạn sẽ nắm được.
Zustand là gì?
Zustand là một thư viện quản lý trạng thái nhẹ cho React, được phát triển bởi nhóm pmndrs. Nó cung cấp một API đơn giản, linh hoạt và hiệu suất cao, giúp bạn quản lý trạng thái một cách dễ dàng mà không cần phải viết nhiều code phức tạp.
Tại sao bạn nên chọn Zustand?
- Kích thước nhỏ (~1KB nén gzip) và hiệu suất cao.
- Dễ tích hợp và sử dụng trong ứng dụng, không cần nhiều cấu hình.
- Tránh được các vấn đề render lại không cần thiết.
- Phù hợp với nhiều loại dự án, từ nhỏ đến lớn.
Ví dụ như thay vì bạn phải viết nhiều reducer và action như trong Redux, với Zustand, bạn chỉ cần định nghĩa state và các action một cách đơn giản.
Hướng dẫn sử dụng Zustand trong dự án NextJS
Để tạo một dự án NextJS cơ bản, bạn có thể tham khảo thêm tại đây
Tiếp theo, bạn hãy chạy câu lệnh bên dưới để cài đặt zustand nha
pnpm install zustand
Nếu như bạn sử dụng TypeScript, cũng không cần cài đặt thêm vì Zustand đã bao gồm phần định nghĩa TypeScript rồi nhé.
- Tạo và sử dụng Store trong Zustand
Trong Zustand, store là nơi lưu trữ trạng thái của ứng dụng. Bạn có thể tạo nhiều store tùy theo nhu cầu, và mỗi store là một hook sử dụng trong component.
Cấu trúc chung của một store trong Zustand sẽ trông như thế này:
import create from 'zustand';
interface State {
// Định nghĩa state
}
const useStore = create<State>((set) => ({
// Khởi tạo state và action
}));
export default useStore;
Cụ thể hơn thì đoạn code trông như thế này:
// stores/counterStore.ts
import create from 'zustand';
interface CounterState {
count: number;
increase: () => void;
decrease: () => void;
reset: () => void;
}
const useCounterStore = create<CounterState>((set) => ({
count: 0,
increase: () => set((state) => ({ count: state.count + 1 })),
decrease: () => set((state) => ({ count: state.count - 1 })),
reset: () => set({ count: 0 }),
}));
export default useCounterStore;
import create from 'zustand'
: dùng để tạo store.
interface CounterState: định nghĩa type cho state và các actions trong store. Lý do bạn nên định nghĩa type để dễ bảo trì, an toàn, hỗ trợ IntelliSense.
- count: number: lưu trữ số đếm.
- increase: () => void: hàm tăng số đếm.
- decrease: () => void: hàm giảm số đếm.
- reset: () => void: hàm đặt lại số đếm.
const useCounterStore = create<CounterState>((set) => ({ ... })): tạo store với type CounterState.
- set: hàm dùng để cập nhật trạng thái
- Khởi tạo giá trị ban đầu của count là 0.
- increase: () => set((state) => ({ count: state.count + 1 })): cập nhật state
- (state) => ({ count: state.count + 1 }): hàm nhận trạng thái hiện tại và trả về trạng thái mới với count tăng lên 1.
Sử dụng Store trong component:
// pages/index.tsx
import React from 'react';
import useCounterStore from '../stores/counterStore';
const HomePage: React.FC = () => {
// get count value from store
const count = useCounterStore((state) => state.count);
// action from store
const increase = useCounterStore((state) => state.increase);
const decrease = useCounterStore((state) => state.decrease);
const reset = useCounterStore((state) => state.reset);
return (
<div style={{ textAlign: 'center', marginTop: '50px' }}>
<h1>Giá trị đếm: {count}</h1>
<button onClick={increase} class="btn btn-primary mx-1">Tăng</button>
<button onClick={decrease} class="btn btn-secondary mx-1">Giảm</button>
<button onClick={reset} class="btn btn-danger mx-1">Đặt lại</button>
</div>
);
};
export default HomePage;