Trong React, Reducer là một công cụ mạnh mẽ để tối ưu hóa quy trình quản lý state
của các component
. Context cho phép bạn truyền dữ liệu từ component
cha đến các component
khác sâu bên trong nó. Bài viết này sẽ hướng dẫn bạn cách kết hợp Reducer và Context để quản lý state
của một màn hình phức tạp mà không cần truyền state
và props
.
Kết hợp Reducer với Context
Kết hợp Reducer và Context trong React cho phép bạn quản lý state
của ứng dụng một cách hiệu quả và tránh việc truyền state
và props
qua nhiều component
con. Điều này trở nên quan trọng khi ứng dụng phức tạp và có nhiều component
ở giữa.
Bước 1: Tạo Context
Trước tiên, bạn cần tạo Context bằng cách sử dụng hàm createContext
từ thư viện React. Trong ví dụ này, chúng ta sẽ tạo hai Context: TasksContext
để cung cấp danh sách các công việc và TasksDispatchContext
để cung cấp hàm điều khiển để thay đổi danh sách này.
jsx
import { createContext } from "react";
export const TasksContext = createContext(null);
export const TasksDispatchContext = createContext(null);
Bước 2: Đặt state
và hàm điều khiển vào Context
Bây giờ, bạn có thể nhập cả hai Context
này vào component TaskApp
. Trong ví dụ này, state tasks
và hàm dispatch
được quản lý bởi Reducer sẽ được cung cấp cho toàn bộ cây component
dưới đó.
jsx
import { TasksContext, TasksDispatchContext } from "./TasksContext.js";
export default function TaskApp() {
const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);
return (
<TasksContext.Provider value={tasks}>
<TasksDispatchContext.Provider value={dispatch}>
{/* Các `component` con ở đây */}
</TasksDispatchContext.Provider>
</TasksContext.Provider>
);
}
Bước 3: Sử dụng Context trong cây component
Bây giờ, bạn không cần phải truyền danh sách công việc và các hàm điều khiển xuống cây component
nữa. Thay vào đó, bất kỳ component
con nào cần đọc danh sách công việc có thể sử dụng TasksContext
để truy cập nó.
jsx
export default function TaskList() {
const tasks = useContext(TasksContext);
// ...
}
function Task({ task }) {
const [isEditing, setIsEditing] = useState(false);
const dispatch = useContext(TasksDispatchContext);
// ...
}
Lưu ý khi sử dụng Reducer và Context
Để làm cho mã nguồn dễ quản lý hơn, bạn có thể tách cả Reducer
và Context
vào một tệp duy nhất. Trong ví dụ này, tệp TasksContext.js
chứa cả hai Context và Reducer, cùng với một component
TasksProvider
để quản lý state
và cung cấp Context.
jsx
// TasksContext.js
import { createContext, useReducer, useContext } from "react";
// Khởi tạo Context
export const TasksContext = createContext(null);
export const TasksDispatchContext = createContext(null);
// Reducer và khởi tạo `state` ban đầu
const initialTasks = [];
const tasksReducer = (state, action) => {
// Xử lý các hành động
};
// Thành phần cung cấp Context và Reducer
export function TasksProvider({ children }) {
const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);
return (
<TasksContext.Provider value={tasks}>
<TasksDispatchContext.Provider value={dispatch}>
{children}
</TasksDispatchContext.Provider>
</TasksContext.Provider>
);
}
// Các hàm tùy chỉnh để đọc Context
export function useTasks() {
return useContext(TasksContext);
}
export function useTasksDispatch() {
return useContext(TasksDispatchContext);
}
Bây giờ, mã nguồn của các component
trở nên gọn gàng và không còn phải quan tâm đến việc truyền state
và hàm điều khiển qua props.
Kết hợp Reducer và Context trong React giúp bạn quản lý state
của ứng dụng một cách hiệu quả và tối ưu hóa quy trình làm việc. Bằng cách tạo các Context cho state
và hàm điều khiển, bạn có thể truy cập chúng từ bất kỳ component
nào trong cây component
mà không cần truyền chúng qua props. Điều này giúp làm cho mã nguồn dễ đọc và bảo trì hơn khi ứng dụng của bạn phức tạp lên.
Bài tập
Bài tập 1: Tạo một ứng dụng To-Do List sử dụng useContext
và useReducer
-
Khởi tạo Context và Reducer:
- Tạo một
TodoContext
sử dụngcreateContext
. - Xác định một
reducer
để quản lý các hành động như thêm, xóa, và cập nhật trạng thái của một công việc.
- Tạo một
-
Tạo Provider:
- Sử dụng
TodoContext.Provider
để bao bọc ứng dụng của bạn và truyềnstate
vàdispatch
từuseReducer
như giá trị.
- Sử dụng
-
Tạo các Components:
TodoList
: Hiển thị danh sách công việc.TodoItem
: Hiển thị từng công việc và nút để đánh dấu hoàn thành hoặc xóa.AddTodo
: Form để thêm công việc mới.
-
Thực hiện các hành động:
- Sử dụng
dispatch
để gửi các hành động đếnreducer
từ các components.
- Sử dụng
Bài tập 2: Tạo một ứng dụng quản lý trạng thái đăng nhập
-
Khởi tạo State và Reducer:
- Tạo một
AuthContext
và mộtauthReducer
để quản lý trạng thái đăng nhập, bao gồm thông tin người dùng và token.
- Tạo một
-
Xử lý Đăng nhập/Đăng xuất:
- Tạo một form đăng nhập và sử dụng
dispatch
để gửi hành động đăng nhập. - Khi đăng nhập thành công, cập nhật trạng thái và lưu token vào context.
- Tạo một nút đăng xuất để gửi hành động đăng xuất và xóa thông tin người dùng khỏi context.
- Tạo một form đăng nhập và sử dụng