JavaScript in Plain English

New JavaScript and Web Development content every day. Follow to join our 3.5M+ monthly readers.

Follow publication

Large File Uploads in the Background with React Native

Photo by Mike van den Bos on Unsplash

React Native, a popular framework for building cross-platform mobile applications empowers developers to create seamless user experiences. In this article, we will dissect a crucial piece of code, a file upload component utilizing background processing, helping you understand its structure, functionality, and potential applications.

Uploading large files in a mobile application is often a complex task that demands a careful balance between user experience and efficient resource management. In React Native, handling asynchronous tasks, especially those involving large data sets, can be challenging. This article dives into a robust solution for large file uploads in React Native while your application is in the background.

First, let’s discuss the dependencies and approach

Dependencies:

I don’t want to bore you with the description of these as they are pretty self-explanatory. When we use these they will become clear.

Approach

The first step to uploading a file is to get the file first, the code that I will give you is an independent component that takes the file as input.

Technically the input is supposed to come from some kind of picker like react-native-document-picker’, you can just pass the selected file from it to the UploadFile component.

Once we have access to the file we will read the file in chunks and then send those chunks to the backend.

Enough talking, let’s get to code! 🧑‍💻

handleUpload

const handleUpload = async (filePath: string) => {
const options = {
taskName: 'FileUpload',
taskTitle: 'Uploading File',
taskDesc: 'Progress',
taskIcon: {
name: 'ic_launcher',
type: 'mipmap',
},
color: '#ff00ff',
//change this for opening the app from notification
linkingURI: 'uploadFile',
};
await BackgroundService.start(() => uploadFileInChunks(filePath), options);
};

This function will run when the user clicks the Upload button and we will send filePath to this function. The options object that we have created is required by the react-native-background-actions library. After that, we are starting a BackgroundService. As the name suggests this will start a service that will run a function in the background. This function will be uploadFileInChunks in our case, which we will work on next.

There are several configurations that you can do using options, for that refer to the docs: https://github.com/Rapsssito/react-native-background-actions?tab=readme-ov-file#options

UploadFileInChunks

Coming to the paneer part (I am vegetarian so can’t write meat!), jokes aside, this function is where we will break the file into chunks and start to send it to our backend chunk by chunk.

Without going into much literature, here is the code

const uploadFileInChunks = async (filePath: string) => {
const uploadUrl =
'https://example.com/upload';
const chunkSize = 1023; //READ THE POINTS BELOW THE CODE
const currentFile = selectedFile[0]; //File which we are getting from our picker

try {
const fileSize = currentFile.size;
let offset = 0;
while (offset < fileSize) {
//here we are reading only a small chunk of the file.
const chunk = await RNFS.read(filePath, chunkSize, offset, 'base64');
const requestBody = {
fileContent: chunk,
offset: offset.toString(),
totalSize: fileSize.toString(),
};

await axios({
method: 'POST',
url: uploadUrl,
headers: {
Authorization:
'Bearer YOUR_TOKEN_HERE',
'Content-Type': 'application/json', // since we are sending base64 in JSON format
},
data: JSON.stringify(requestBody),
});

let percentage = Math.round((offset / fileSize) * 100);
console.log('filesize, offset ', fileSize, offset);
await BackgroundService.updateNotification({
progressBar: {
max: 100,
value: percentage,
},
taskDesc: `Uploading file: ${percentage}% completed`,
});
offset += chunkSize;
}
console.log('Upload complete');
await BackgroundService.updateNotification({
taskDesc: 'File Uploaded',
});
} catch (error) {
console.error('Error during chunk upload:', error);
await BackgroundService.updateNotification({
taskDesc: 'File upload Failed',
});
}
};

Some points to remember

Our whole concept is to divide the file into chunks, but this raises another question. What should be the size of the chunk? Well, my honest answer would be to try different sizes and see what difference it creates.

For those in a hurry, here’s the tl;dr

If you create a chunk of 1kb as I have in this code then your upload will be very slow because you are calling the API for every 1kb of data, that’s a total waste. APIs can easily handle much more than that. With my experimentation, I have found the chunk size ~500kb to be a good match.

NOTE: For base64 the chunk size should be a multiple of 3. Please go through this (~1min) https://stackoverflow.com/a/7920834

That’s it

Now you have a working solution for your application where you can upload files to your backend in base64 format and it will also show you a progress notification while doing so in the background 😌

If you liked this article, give it a clap. You can follow me on your suited platform https://theshubhagrwl.in/ 😄

In Plain English 🚀

Thank you for being a part of the In Plain English community! Before you go:

Published in JavaScript in Plain English

New JavaScript and Web Development content every day. Follow to join our 3.5M+ monthly readers.

Responses (1)

Write a response

Hi, when we do that it blocking the UI completely. I am using 1 gb of file. I am using chuck size 5mb. Bcz s3 multipart min required is 5mb. Any solution?

--