Upload Files Using React Native and Firebase (Part 4)

Track upload progress and download files

Younes Henni, PhD
Jan 12 · 5 min read
Photo by Maarten van den Heuvel on Unsplash

Overview

In the previous parts, you learned how to set up a Firebase Storage service and wrote custom rules for your storage bucket. You also learned how to use Image Picker to upload photos locally and use the storage API to save photos to your bucket.

In this last part of the series, I’ll show you the following.

  • How to monitor the upload progress of your photo.

You can find the full code in here.

Let us jump into it.


1. Monitor upload progress

As a reminder, here is the full code we wrote in part 3 of the series in UploafFile/index.js.

Code in UploadFile/index.js so far

Make the following changes to the uploadFile function.

You no longer need to resolve the promise nor set the local state for the image URI. These two steps will be outsourced to a function called monitorFileUpload that you’re going to write shortly.

You’re now saving the results of uploadFileToFirebase in a variable called uploadTask and passing it as a parameter to monitorFileUpload.

Add the following code just on top of the uploadFile function.

const monitorFileUpload = uploadTask => {
uploadTask.on('state_changed', snapshot => {
switch (snapshot.state) {
case 'running':
setImageURI(null);
break;
case 'success':
snapshot.ref.getDownloadURL().then(downloadURL => {
setImageURI({ uri: downloadURL });
});
break;
default:
break;
}
});
};
const uploadFile = () => // ..

The above function takes uploadTask as the argument and uses an observer method on('state_changed', callback) to track state changes. The observer takes two arguments. The first argument is a string parameter, state_changed, and the second argument is a callback with a snapshot parameter.

You can find more info on tracking upload progress in the official docs here.

With a switch statement, we check snapshot.state for its different cases (i.e., running, success) and update our logic accordingly.

In case of snapshot.state returns a success message, we use snapshot.ref.getDownloadURL() to get the remote URL of the uploaded file. We then set the local state to that URL.

Time to test the app. Refresh your simulator, and add a new post. After waiting for a while (until the photo is uploaded and the remote URL is created), you should see the photo displayed on the screen.


2. Build the progress bar and a skeleton placeholder

As a best practice, you want to show users a progress bar while waiting for the photo to be fetched from storage. To do this, I’ll show you how to leverage the task.on() observer function to build a progress bar for your app.

Start by adding the following function in utils/index.js.

export const uploadProgress = ratio => Math.round(ratio * 100);

The above function takes a ratio parameter then returns a rounded percentage.

Add it to the imports in UploadFile/index.js.

import {
imagePickerOptions,
uploadFileToFireBase,
uploadProgress,
} from '../../utils';

At this point, you need two things.

  • Set the value of the upload progress using the local state.

Add the following code for local state (marked in bold) inside the UploadFile component.

const [upload, setUpload] = useState({
loading: false,
progress: 0,
});
const [imageURI, setImageURI] = useState(null);

Update monitorFileUpload with the following code (marked in bold).

const monitorFileUpload = task => {
task.on('state_changed', snapshot => {
const progress = uploadProgress(
snapshot.bytesTransferred / snapshot.totalBytes
);

switch (snapshot.state) {
case 'running':
setImageURI(null);
setUpload({ loading: true, progress });
break;
case 'success':
snapshot.ref.getDownloadURL().then(downloadURL => {
setImageURI({ uri: downloadURL });
setUpload({ loading: false });
});
break;
default:
break;
}
});
};

As you see above, we can access the bytesTransferred and totalBytes through the snapshot parameter.

We pass the ratio snapshot.bytesTransferred/snapshot.totalBytes to the uploadProgress defined in utils/index.js to get the percentage of the upload progress.

In case the upload is still running, we set loading to true and we save progress to the local state. When the upload is successful, we set loading to false.

Add the following code (marked in bold) inside the return() statement.

return (
<Container>
<StatusBar barStyle="dark-content" />
<Button title="New Post" onPress={uploadFile} color="green" />
{imageURI && <Picture source={imageURI} />}
{upload.loading && (
<>
<Skeleton />
<ProgressBar bar={upload.progress} />
</>
)}
</Container>
);

Whenever upload.loadingis true, we display a Skeleton component and a ProgressBar component (to be defined shortly).

Notice that ProgressBar takes the props bar={upload.progress} to be used to set the width of the bar.

Let us define the Skeleton and ProgressBar styled-components. Add the following (marked in bold) into styles/index.js.

import styled from 'styled-components/native';export const Container = styled.SafeAreaView`
flex: 1;
justify-content: center;
`;
export const Picture = styled.Image.attrs({
resizeMode: 'contain',
})`
height: 300;
width: 100%;
`;
export const ProgressBar = styled.View`
background-color: #039ae5;
height: 3;
width: ${props => props.bar}%;
align-items: flex-start;
`;
export const Skeleton = styled.View`
height: 300;
width: 100%;
background-color: #ebebeb;
`;

Notice the dynamic width of ProgressBar takes the bar props you defined earlier.

Import these two new components in UploadFile/index.js.

import { Container, Picture, Skeleton, ProgressBar } from '../../styles';

The final code in UploadFile/index.js should look like this.

The entire logic in UploadFile/index.js

Time to test your app. Launch or refresh your simulator, and add a new photo.

Image Picker with Firebase Storage and progress bar to track upload

As you can see, a skeleton placeholder with a blue progress bar is shown while the photo is uploaded to storage.


Conclusion

Congratulations on completing this series of tutorials.

You learned how to use react-native-image-picker to upload photos from your mobile device to Firebase Storage. You then learned how to track the upload progress and display a skeleton placeholder with a progress bar. When the upload is successful, you learned how to fetch the photo from its remote URL and displayed it on the screen.

I hope you enjoyed it. Take care, and see you in the next one.

Better Programming

Advice for programmers.

Younes Henni, PhD

Written by

#Physicist turned #Software #Engineer. My blogs cover #Mobile #Apps #Development #JavaScript #ReactNative #GraphQL #Serverless #Technology and #Productivity.

Better Programming

Advice for programmers.

More From Medium

More from Better Programming

More from Better Programming

More from Better Programming

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade