Tối ưu hóa quy trình upload file đa nền tảng: Kết hợp React web và React Native để tạo quy trình upload file mạnh mẽ, có khả năng mở rộng

14 lượt xem · 2 trả lời

1. 18:29 09/10/2026
Quy trình upload file là một trong những tính năng phổ biến trong hầu hết các ứng dụng web và di động hiện đại. Việc xây dựng quy trình này một cách mạnh mẽ và có khả năng mở rộng không chỉ giúp cải thiện trải nghiệm người dùng mà còn đảm bảo sự ổn định của hệ thống khi xử lý nhiều tệp cùng lúc. **1. Xác định các yêu cầu chính** - **Kích thước và loại tệp**: Kiểm tra kích thước tối đa, giới hạn số lượng tệp và danh sách các MIME type được phép. - **Theo dõi tiến trình**: Cung cấp cho người dùng phản hồi trực quan về tiến trình tải lên. - **Xử lý lỗi**: Phát hiện các lỗi mạng, lỗi máy chủ hoặc lỗi xác thực và cung cấp các tùy chọn để thử lại. - **Tái sử dụng logic**: Chia sẻ validation, xử lý tiến trình và tích hợp server giữa các dự án React web và React Native. **2. Validation ở phía client** Hãy bắt đầu bằng một custom hook có thể tái sử dụng: ```js // useFileValidation.js import { useState, useCallback } from 'react'; const useFileValidation = (maxSize, acceptedTypes) => { const [error, setError] = useState(null); const validate = useCallback((file) => { if (!file) { setError('Không có tệp nào được chọn.'); return false; } if (maxSize && file.size > maxSize) { setError(`Kích thước tệp vượt quá giới hạn ${maxSize} byte.`); return false; } if (acceptedTypes && !acceptedTypes.includes(file.type)) { setError('Loại tệp không được hỗ trợ.'); return false; } setError(null); return true; }, [maxSize, acceptedTypes]); return { error, validate }; }; ``` Hook này có thể được sử dụng trong cả React web (qua HTMLInputElement) và React Native (qua react-native-document-picker). **3. Theo dõi tiến trình tải lên** Đối với React web, API FormData hỗ trợ sự kiện progress: ```js const upload = async (file) => { const formData = new FormData(); formData.append('file', file); const xhr = new XMLHttpRequest(); xhr.upload.addEventListener('progress', (e) => { const percent = Math.round((e.loaded / e.total) * 100); // Cập nhật trạng thái tiến trình }); // Xử lý kết quả }; ``` Trong React Native, bạn có thể sử dụng `fetch` với đối tượng `progress` tương tự hoặc thư viện `aws-sdk` cho các trường hợp sử dụng S3. **4. Xử lý lỗi và thử lại** Tạo một wrapper component bao quanh quy trình tải lên: ```js const RobustUploader = ({ onSuccess }) => { const [uploading, setUploading] = useState(false); const [progress, setProgress] = useState(0); const { error, validate } = useFileValidation(5 * 1024 * 1024, ['image/*']); const handleUpload = async (selectedFile) => { if (!validate(selectedFile)) return; setUploading(true); try { await uploadWithRetry(selectedFile, { progress: setProgress, onSuccess }); } catch (e) { // Hiển thị thông báo lỗi } finally { setUploading(false); } }; const uploadWithRetry = async (file, callbacks, attempts = 3) => { for (let i = 0; i < attempts; i++) { try { await performUpload(file, callbacks); return; } catch (err) { if (i === attempts - 1) throw err; // chờ trước khi thử lại } } }; }; ``` **5. Chia sẻ logic thông qua Context** Tạo một `UploadContext` để cung cấp state upload, hàm validation và hàm upload cho toàn bộ cây component. Điều này giúp các screen hoặc native modules có thể truy cập cùng một logic mà không cần prop drilling. **6. Triển khai và kiểm tra** - **Kiểm tra validation**: Sử dụng Jest + React Testing Library để mô phỏng các tệp hợp lệ và không hợp lệ. - **Kiểm tra tiến trình**: Mô phỏng sự kiện `progress` của XHR/fetch. - **Kiểm tra tích hợp server**: Sử dụng Mock Service Worker để mô phỏng các endpoint thành công, lỗi 5xx và giới hạn tốc độ mạng. Bằng cách tuân thủ các bước trên, bạn có thể xây dựng quy trình upload file vừa mạnh mẽ vừa linh hoạt, hoạt động đồng nhất trên React web và React Native. Điều này không chỉ mang lại trải nghiệm người dùng mượt mà mà còn tạo nền tảng cho các tính năng nâng cao trong tương lai (như upload hàng loạt, xử lý trước tệp trên client hoặc tích hợp cloud).
0 Facebook
2. 19:10 25/10/2026
Trả lời Quản Trị Viên Quy trình upload file là một trong những tính năng phổ biến trong hầu hết các ứng dụng web và di động hiện đại. Việc xây…
Bài viết có khung khá thực tế, nhưng mình muốn bổ sung hai điểm dễ gây lỗi khi triển khai. Thứ nhất, `acceptedTypes.includes(file.type)` sẽ không khớp với `'image/*'` vì `file.type` thường là `'image/png'` hoặc `'image/jpeg'`. Nên viết hàm so khớp wildcard, hoặc kiểm tra theo phần mở rộng kết hợp MIME; quan trọng hơn, server vẫn phải validate lại vì MIME do client gửi lên có thể bị giả. Thứ hai, trong React Native, `fetch` không hỗ trợ theo dõi tiến trình upload như XHR trên web. Cách thực tế hơn là dùng `XMLHttpRequest`, `react-native-blob-util`, hoặc upload trực tiếp lên S3 bằng presigned URL để giảm tải cho server. Phần retry cũng nên phân biệt lỗi mạng/5xx với lỗi 4xx; chỉ retry các trường hợp có khả năng thành công và dùng backoff để tránh dồn
0
3. 16:22 26/10/2026
Trả lời Kate Miller Bài viết có khung khá thực tế, nhưng mình muốn bổ sung hai điểm dễ gây lỗi khi triển khai. Thứ nhất, `acceptedTypes.incl…
Mình đồng ý với hai điểm bạn nêu, nhất là chuyện kiểm tra MIME ở client chỉ nên xem là lớp UX. Với wildcard, có thể viết hàm tách type/subtype rồi so khớp: nếu pattern kết thúc bằng “/*” thì chỉ so phần type; còn lại so khớp chính xác. Nhưng server vẫn nên kiểm tra thêm magic bytes, kích thước, số lượng file và giới hạn loại file thực sự cho phép, vì cả MIME lẫn phần mở rộng đều có thể bị giả. Về React Native, XHR vẫn là cách nhẹ để có upload.onprogress; với file lớn hoặc cần ổn định hơn thì react-native-blob-util hoặc presigned URL lên S3 là hợp lý. Nếu dùng presigned URL, nên cân nhắc multipart upload, abort/retry từng part và kiểm tra CORS. Phần retry mình cũng làm tương tự: chỉ retry lỗi mạng, timeout, 408, 429 và 5xx; tôn trọng Retry-After nếu có; dùng exponential backoff kèm jitter và giới hạn số lần thử. Với
0
Vui lòng đăng nhập để tham gia trả lời chủ đề này.
Điều hướng nhanh

Bạn muốn khám phá điều gì?

Tìm chủ đề, bài viết hoặc đi thẳng đến một khu vực của cộng đồng.

Esc để đóng Ctrl K để mở lại