When you’re building a cross‑platform app with React and React Native, handling file uploads can become a bottleneck if you don’t plan ahead. A solid workflow balances validation, progress tracking, error handling, and server integration while keeping the UI consistent across web and mobile. **Key Principles** - **Consistent Logic** – Share validation rules and upload services between the web and native layers to avoid duplicated code and bugs. - **Progressive Validation** – Perform lightweight client‑side checks first (file type, size, basic format) and only send detailed validation to the server when needed. - **Clear Feedback** – Show users a visual progress bar, success or error messages, and the ability to retry failed uploads. - **Scalable Architecture** – Use a reducer or state‑management library (e.g., Zustand, Redux) to manage upload queues, so you can handle dozens or hundreds of concurrent uploads without blocking the UI. **Practical Implementation Steps** 1. **Define Shared Types** ```ts export interface UploadFile { id: string; file: File; progress: number; status: 'pending' | 'uploading' | 'success' | 'error'; error?: string; } ``` Placing these definitions in a shared “types” folder ensures both React web and React Native projects reference the same shape. 2. **Create a Custom Hook for Upload Logic** Build a hook like `useFileUpload` that returns an array of `UploadFile` and functions such as `addFiles`, `removeFile`, `retryUpload`. Use React’s `useReducer` to keep the upload queue predictable. 3. **Leverage Context for Global State** Wrap the app in an `UploadContext`. Components can consume the context to display upload lists, drag‑and‑drop areas, or integrate with navigation flows on mobile. 4. **Integrate with a Backend Service** Use a unified API endpoint (e.g., `/api/upload`) that accepts multipart/form‑data. On the client, `FormData` is built from the file object and sent via `axios` or the native `fetch` API. Include an `X-Upload-ID` header to tie multiple chunks or parallel uploads together. 5. **Handle Progress and Errors** - **Progress**: Listen to the `progress` event on the XMLHttpRequest/Fetch request and update the store accordingly. - **Errors**: Capture HTTP status codes, network failures, or server‑side validation errors. Store the error message in the `UploadFile` state and provide a retry button. **Best Practices** - **Debounced Validation** – Run size or type checks after a short delay when the user stops selecting files, preventing unnecessary processing. - **Upload Queues** – Limit concurrent uploads (e.g., max 3 at a time) to avoid overwhelming the server and the device’s network stack. - **Offline Support** – Store pending uploads in `AsyncStorage` or `localStorage` so the app can retry them when connectivity returns. - **Security** – Never expose raw file paths to the client. Sanitize filenames on the server and consider using signed URLs for direct cloud storage uploads. By following these patterns you’ll get a reusable, testable, and maintainable upload system that works smoothly on React web and React Native, delivering a professional user experience across all platforms.