1. 15:41 06/10/2026
Khi các ứng dụng React phát triển, việc quản lý trạng thái một cách hiệu quả trở thành yếu tố then chốt để đảm bảo hiệu suất cao và trải nghiệm người dùng mượt mà. Redux Toolkit (RTK) cung cấp một bộ công cụ được thiết kế sẵn để giúp việc quản lý trạng thái trở nên đơn giản hơn mà không phải hy sinh khả năng mở rộng. Dưới đây là hướng dẫn thực hành giúp bạn thiết lập một cấu trúc quản lý trạng thái mạnh mẽ, sẵn sàng cho các ứng dụng quy mô lớn.
**1. Thiết lập cấu trúc thư mục
• src/store/ – chứa toàn bộ logic của Redux
◦ reducers.ts – tổng hợp tất cả reducers
◦ store.ts – cấu hình store với middleware
• src/features/ – phân tách trạng thái theo tính năng (ví dụ: người dùng, bài viết, bình luận)
◦ featureSlice.ts – tạo slice riêng biệt cho từng tính năng
◦ featureAPI.ts – các endpoint RTK Query hoặc thunks được tạo sẵn
Cách tiếp cận này giúp việc tìm kiếm các đoạn mã liên quan trở nên dễ dàng hơn và hạn chế sự chồng chéo giữa các tính năng.
**2. Tạo slice với Redux Toolkit
Sử dụng createSlice để định nghĩa reducers và actions trong cùng một tệp. Điều này giúp đảm bảo tính nhất quán giữa tên actions và reducers.
```ts
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
interface UserState {
data: User | null;
loading: boolean;
error: string | null;
}
const initialState: UserState = { data: null, loading: false, error: null };
const userSlice = createSlice({
name: 'user',
initialState,
reducers: {
setUser(state, action: PayloadAction<User>) { state.data = action.payload; },
setLoading(state, action: PayloadAction<boolean>) { state.loading = action.payload; },
setError(state, action: PayloadAction<string | null>) { state.error = action.payload; },
},
});
export const { setUser, setLoading, setError } = userSlice.actions;
export default userSlice.reducer;
```
**3. Tích hợp RTK Query để gọi API
RTK Query giúp loại bỏ nhu cầu viết mã thunks một cách thủ công. Hãy xác định các endpoint và tự động tích hợp chúng với store.
```ts
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
export const userAPI = createApi({
reducerPath: 'userAPI',
baseQuery: fetchBaseQuery({ baseUrl: 'https://api.example.com/' }),
endpoints: (builder) => ({
getCurrentUser: builder.query<User, void>({ query: () => 'me' }),
}),
});
export const { useGetCurrentUserQuery } = userAPI;
```
**4. Tối ưu hóa việc tải dữ liệu
• Sử dụng **lấy dữ liệu theo yêu cầu** để chỉ lấy dữ liệu cần thiết cho từng màn hình.
• Bọc các component hiển thị dữ liệu trong hook `useGetCurrentUserQuery`. Component sẽ tự động render lại khi dữ liệu được cập nhật.
• Triển khai **lấy dữ liệu song song** khi nhiều endpoint được gọi trong cùng một component:
```ts
const Dashboard = () => {
const { data: user } = useGetCurrentUserQuery();
const { data: stats } = useGetDashboardStatsQuery();
if (!user || !stats) return <Spinner />;
// render logic
};
```
**5. Áp dụng cơ chế thử lại và xử lý lỗi
RTK Query đã bao gồm cơ chế thử lại tự động cho các lỗi mạng. Bạn có thể tùy chỉnh hành vi này:
```ts
export const userAPI = createApi({
…,
prepareHeaders: (headers) => {
headers.set('Authorization', `Bearer ${token}`);
return headers;
},
keepUnusedDataFor: 60, // giữ dữ liệu trong cache trong 60 giây
});
```
**6. Tích hợp với React DevTools
Để theo dõi trạng thái và actions một cách dễ dàng, hãy bao gồm extension của React DevTools và RTK Redux DevTools.
**7. Triển khai kiểm thử
• Sử dụng **React Testing Library** để kiểm thử các component với store được cung cấp.
• Viết unit tests cho reducers với Jest.
**8. Tối ưu hóa hiệu suất
• Sử dụng **selectors** có tính tham chiếu để tránh render lại không cần thiết.
• Tích hợp **code splitting** với React.lazy để tải các component một cách lười biếng.
• Sử dụng **memoization** (React.memo, useMemo, useCallback) trong các component hiển thị dữ liệu.
**Kết luận**
Bằng cách tuân thủ cấu trúc thư mục rõ ràng, sử dụng RTK Query để xử lý API và áp dụng các phương pháp hay nhất về kiểm thử và tối ưu hóa, bạn có thể xây dựng một giải pháp quản lý trạng thái có thể mở rộng và dễ bảo trì cho các ứng dụng React. Cách tiếp cận này không chỉ giúp giảm thiểu việc viết mã trùng lặp mà còn đảm bảo ứng dụng của bạn luôn sẵn sàng cho các tính năng và lưu lượng truy cập trong tương lai.
**Lời khuyên nhanh**
- Bắt đầu với createSlice; nó sẽ giúp bạn tiết kiệm rất nhiều thời gian.
- Luôn bao bọc các component hiển thị dữ liệu trạng thái bằng hook từ RTK Query.
- Triển khai cơ chế thử lại tùy chỉnh cho các trường hợp ngoại lệ của mạng.
- Luôn theo dõi trạng thái thông qua Redux DevTools trong quá trình phát triển.
- Sử dụng selectors có tính tham chiếu để tối ưu hóa quá trình render lại component.