1. 19:42 10/10/2026
Trong các dự án React đa nền tảng, việc duy trì một quy trình upload file thống nhất trên Web và Mobile có thể là một thách thức. Mã trùng lặp không chỉ làm tăng khối lượng công việc mà còn dễ dẫn đến sai sót khi một nền tảng được cập nhật trong khi nền tảng kia thì không. Trong bài viết này, chúng ta sẽ khám phá một phương pháp tiếp cận thực tế để đồng bộ hóa logic upload file bằng cách kết hợp custom hooks, Context API, React Hook Form và React Query.
**Tại sao cần một hook upload chung?**
- **DRY (Don't Repeat Yourself):** Triển khai logic xử lý file, tải lên và quản lý trạng thái chỉ một lần.
- **Đồng bộ UI/UX:** Đảm bảo người dùng nhận được phản hồi giống nhau, cho dù họ đang sử dụng trình duyệt hay ứng dụng di động.
- **Khả năng kiểm thử:** Hook có thể tái sử dụng giúp việc viết unit test trở nên dễ dàng hơn.
**Các bước triển khai**
1. **Tạo hook upload trung tâm (`useUpload.ts`)**
```typescript
const useUpload = () => {
const { register, handleSubmit, formState: { errors } } = useForm();
const { data, error, isLoading, mutate } = useMutation(
async (file: File) => {
const formData = new FormData();
formData.append('file', file);
const res = await api.upload(formData);
return res.data;
}
);
// Trả về các hàm và trạng thái cần thiết cho component
return { register, handleSubmit, errors, data, error, isLoading, mutate };
};
```
Hook này tích hợp React Hook Form để quản lý form và React Query để xử lý việc tải lên bất đồng bộ, caching và khả năng làm mới dữ liệu.
2. **Xác định kiểu dữ liệu chia sẻ (`UploadContext.ts`)**
```typescript
interface UploadState {
progress: number;
status: 'idle' | 'uploading' | 'success' | 'error';
message?: string;
}
```
Việc xác định rõ các trạng thái giúp mọi component đều có thể truy cập cùng một ngữ nghĩa.
3. **Bao bọc ứng dụng trong Context Provider**
```typescript
const UploadProvider = ({ children }: { children: React.ReactNode }) => {
const [state, setState] = useState<UploadState>({ progress: 0, status: 'idle' });
return (
<UploadContext.Provider value={{ state, setState }}>{children}</UploadContext.Provider>
);
};
```
4. **Sử dụng hook trong cả hai nền tảng**
Trong component Web:
```tsx
const { register, handleSubmit, errors, mutate } = useUpload();
const onSubmit = handleSubmit(async (data) => {
await mutate(data.file);
});
```
Trong component React Native:
```tsx
const { register, handleSubmit, errors, mutate } = useUpload();
const onSubmit = handleSubmit(async (data) => {
await mutate(data.file);
});
```
**Lời khuyên thực tế**
- **Xác thực file ở đầu:** Giới hạn kích thước, loại file và tên để tránh việc tải lên không cần thiết.
- **Thêm logic thử lại:** Sử dụng `useMutation` với `retry` để xử lý các lỗi mạng tạm thời.
- **Hiển thị tiến trình:** Cập nhật `progress` trong Context để hiển thị thanh tiến trình tải lên trong UI.
- **Xử lý lỗi một cách rõ ràng:** Cung cấp thông báo lỗi cụ thể cho người dùng dựa trên `error` từ React Query.
**Kết luận**
Bằng cách kết hợp custom hooks với Context API, bạn có thể tạo một quy trình upload file đồng bộ, có thể tái sử dụng cho cả React Web và React Native. Phương pháp này không chỉ giúp giảm mã trùng lặp mà còn đảm bảo trải nghiệm người dùng nhất quán và quy trình phát triển dễ bảo trì hơn.