1. 08:09 10/10/2026
Khi xây dựng ứng dụng React yêu cầu chia sẻ logic upload file giữa web và native, việc lặp lại mã hoặc duy trì hai quy trình riêng biệt có thể nhanh chóng dẫn đến lỗi và khó bảo trì. Hướng dẫn này trình bày một phương pháp tiếp cận hiện đại, có thể tái sử dụng để đồng bộ hóa quy trình upload file trên React Web và React Native bằng cách kết hợp React Query, Context API và custom hooks.
**1. Xác định các mối quan tâm cốt lõi**
Trước tiên, hãy xác định những gì bạn cần theo dõi: danh sách tệp đã chọn, tiến trình upload từng tệp, trạng thái lỗi và danh sách các tệp đã upload thành công. Việc xác định các mối quan tâm này giúp bạn xác định phạm vi của Provider, hook và component UI.
**2. Tạo một provider toàn cục**
Tạo `UploadProvider` sử dụng React Context để lưu trữ trạng thái chung:
```tsx
const UploadContext = createContext(null);
function UploadProvider({ children }) {
const [uploads, setUploads] = useState({}); // key: file.id
const mutate = useMutation(uploadFile, {
onSuccess: (data, file) => {
setUploads(prev => ({ ...prev, [file.id]: { ...prev[file.id], status: 'success', data } }));
},
onError: (error, file) => {
setUploads(prev => ({ ...prev, [file.id]: { ...prev[file.id], status: 'error', error } }));
},
});
const addFile = (file) => {
const id = nanoid();
const entry = { id, file, status: 'pending', progress: 0 };
setUploads(prev => ({ ...prev, [id]: entry }));
// Bắt đầu upload
upload(file, {
onProgress: (pct) => setUploads(prev => ({ ...prev, [id]: { ...prev[id], progress: pct } })),
}).then(resp => mutate.mutateAsync({ file, response: resp }));
};
return <UploadContext.Provider value={{ uploads, addFile }}>{children}</UploadContext.Provider>;
}
```
**3. Xây dựng một custom hook có thể tái sử dụng**
`useUpload` bao bọc context để cung cấp giao diện thân thiện với component:
```tsx
function useUpload() {
const ctx = useContext(UploadContext);
if (!ctx) throw new Error('useUpload phải được sử dụng trong UploadProvider');
return ctx;
}
```
**4. Xây dựng các thành phần UI** – Một component `FileUploadArea` duy nhất có thể được render trên cả web (sử dụng HTML thuần túy) và native (sử dụng Pressable / View). Component này sử dụng `useDropzone` cho web và một listener touch cho React Native, sau đó gọi `useUpload().addFile`.
**5. Tích hợp React Query**
React Query xử lý caching, đồng bộ hóa dữ liệu nền và tự động làm mới. Hook `useMutation` được sử dụng trong provider đảm bảo rằng trạng thái upload được phản ánh trong query cache, giúp việc hiển thị danh sách các tệp đã upload trở nên dễ dàng.
**6. Ví dụ về xử lý lỗi và nhiều định dạng**
Xác thực loại tệp ngay trong hook addFile. Đối với các loại không được hỗ trợ, bạn có thể đặt một entry lỗi mà không cần gọi mutate, giúp người dùng có phản hồi tức thì.
**7. Lời khuyên thực tế**
- Sử dụng TypeScript để xác định kiểu cho state và hàm callback.
- Viết các test unit riêng biệt cho hook logic (bỏ qua các wrapper UI).
- Tận dụng `react‑query/devtools` để theo dõi trạng thái upload trong quá trình phát triển.
- Đối với React Native, hãy cân nhắc sử dụng các tính năng riêng của nền tảng (ví dụ: `DocumentPicker`, `CameraRoll`) trong khi vẫn giữ nguyên interface hook.
Bằng cách tuân theo cấu trúc này, bạn sẽ có được một quy trình upload file hiện đại, có thể tái sử dụng, hoạt động trơn tru trên cả web và ứng dụng di động, đồng thời giảm thiểu sự phức tạp trong mã nguồn.