1. 14:59 10/10/2026
**Giới thiệu**
Việc upload file thường là một trong những tác vụ phức tạp nhất trong cả ứng dụng web và di động. Xử lý validation, theo dõi trạng thái, retry và đồng bộ dữ liệu trên nhiều nền tảng có thể nhanh chóng trở nên khó bảo trì nếu không có một kiến trúc rõ ràng. Trong bài viết này, chúng ta sẽ khám phá cách kết hợp React Hook Form để validation, React Query để quản lý và đồng bộ dữ liệu, cùng Context API để chia sẻ trạng thái giữa code Web và Native, từ đó tạo ra một quy trình upload file linh hoạt, dễ kiểm thử và có thể tái sử dụng.
**Tại sao nên kết hợp các công nghệ này?**
- **React Hook Form**: Giảm thiểu việc render lại bằng cách sử dụng schema validation dựa trên Yup hoặc Zod, đồng thời cung cấp API hook tiện lợi cho việc quản lý form.
- **React Query**: Đơn giản hóa việc upload bằng cách xử lý trạng thái (loading, error, success) và tự động refetch dữ liệu sau khi upload hoàn tất.
- **Context API**: Chia sẻ các tác vụ upload chung, danh sách file đã chọn và thông báo lỗi giữa các component web và native mà không cần truyền prop nhiều lần.
**Kiến trúc tổng thể**
1. **Tạo schema validation** – Định nghĩa một schema duy nhất bằng Yup.
2. **Tạo một hook upload chung** – Sử dụng React Hook Form để kết nối form với các input file.
3. **Bao bọc hook trong React Query** – Transform file thành một mutation, tự động xử lý progress và retry.
4. **Tạo một Context provider** – Cung cấp trạng thái upload, danh sách file đã chọn và một hàm helper để trigger upload.
5. **Tái sử dụng component** – Sử dụng cùng một component cho cả web và native (bằng cách sử dụng cùng một hook từ Context).
**Ví dụ thực tế**
```js
// fileUploadSchema.js
import * as yup from 'yup';
export const fileUploadSchema = yup.object().shape({
file: yup
.mixed()
.required('Vui lòng chọn một tệp')
.test('fileSize', 'Tệp quá lớn', (value) => value && value.size <= 5 * 1024 * 1024)
});
```
```js
// useFileUpload.js
import { useForm } from 'react-hook-form';
import { useMutation } from '@tanstack/react-query';
import { uploadFile } from './api';
import { FileUploadContext } from './context';
export const useFileUpload = () => {
const { setFiles, setError } = useContext(FileUploadContext);
const { register, handleSubmit, setValue } = useForm();
const mutation = useMutation({
mutationFn: uploadFile,
onSuccess: (data) => {
setFiles(data.files);
},
onError: (err) => {
setError(err.message);
}
});
const onSubmit = handleSubmit(async (data) => {
mutation.mutate(data.file);
});
return { register, onSubmit, isLoading: mutation.isPending };
};
```
**Lời khuyên để duy trì mã nguồn**
- **Tách biệt schema validation** – Sử dụng một file riêng cho Yup/Zod để cả web và native đều có thể nhập cùng một quy tắc.
- **Tận dụng TypeScript** – Định nghĩa các type chung cho đối tượng upload để đảm bảo tính nhất quán.
- **Tạo một hook helper cho việc retry** – Tích hợp với React Query sẽ tự động xử lý việc này, nhưng bạn có thể tùy chỉnh số lần retry theo từng nền tảng.
- **Tận dụng React-Query Devtools** – Giúp việc debug mutation dễ dàng hơn trên cả hai môi trường.
**Kết luận**
Bằng cách kết hợp React Hook Form, React Query và Context API, bạn có thể xây dựng một quy trình upload file vừa mạnh mẽ vừa linh hoạt. Cách tiếp cận này giúp loại bỏ việc viết mã trùng lặp, cải thiện khả năng kiểm thử và mang lại trải nghiệm người dùng mượt mà trên cả ứng dụng web và di động.