Image Upload Component React Native Expo

Faysal Ahmed
Oceanize Lab Geeks
Published in
5 min readNov 27, 2018

Uploading image from react native to a specific endpoint is very necessary for any react native developer. I will try to describe you how to do this things.

React Native Powerful way to develop mobile application

For this tutorial we will create a new file inside

projectRoot/src/libs/UploadImage.js.

Inside UploadImage.js we will create a basic component

add uuid using below command if not exits

npm install uuid

Create Layout of UploadImage.js and basic styling

import React,{Component} from 'react';
import {
Text,
View,
Dimensions,
ActivityIndicator,
Platform,
Alert,
Linking,
StyleSheet,
Image,
TouchableOpacity,
} from 'react-native';
import { ImagePicker, Permissions } from 'expo';
import uid from 'uuid/v4';
export default class UploadImage extends Component{
constructor(props){
super(props)
this.state={
endpoint:this.props.endpoint
}
defaultProps = {
onSuccess: undefined,
onFailure: undefined,
onStartUpload: undefined,
alertTitle: 'Please Allow Access',
alertMessage: [
'This applicaton needs access to your photo library to upload images.',
'\n\n',
'Please go to Settings of your device and grant permissions to Photos.',
].join(''),
alertNo: 'Not Now',
alertYes: 'Settings',
};
}
render(){
return(
<View style={style.imgwrapper}>
{this.props.callbackUrl != null ? <Image source={{uri: this.state.uploaded_photo ? this.state.uploaded_photo : this.props.callbackUrl}} style={{width: 80, height: 80,borderRadius: 40}}/> : <Image source={{uri:'https://www.royaleboost.com/template/default-profile-img.png'}} style={{width: 80, height: 80}}/> }
<TouchableOpacity
style={style.circleWrapper}
onPress={()=>{
this.uploadResult();
}}
>
<View />
</TouchableOpacity>
</View>
)
}
}
const style = StyleSheet.create({
imgwrapper:{
justifyContent: 'center',
alignItems: 'center',
position:'relative',
marginBottom: 80,
},
circleWrapper:{
backgroundColor:'#ECECEC',
height:22,
width:22,
borderWidth:3,
borderColor: '#ffffff',
borderRadius:11,
marginLeft:70,
marginTop: -80,
},
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
})

Create method for asking permission

async askPermission() {
// only if user allows permission to camera roll
const { status } = await Permissions.askAsync(Permissions.CAMERA_ROLL);
const { onStartUpload } = this.props;
// On Android users are prompted every time,
// so no need to show additional Alert
if (status !== 'granted') {
if (Platform.OS === 'ios') this.showAlert();
return;
}
}

Show permission Alert for IOS:

If there is no permission it will open with an alert for enable the media permission & will guide to phone settings

showAlert() {
const { alertMessage, alertTitle, alertYes, alertNo } = this.props;
Alert.alert(
'Please Allow Access',
[
'This applicaton needs access to your photo library to upload images.',
'\n\n',
'Please go to Settings of your device and grant permissions to Photos.',
].join(''),
[
{ text: 'Not Now', style: 'cancel' },
{ text: 'Settings', onPress: () => Linking.openURL('app-settings:') },
],
);
}

On Press Start Upload Method:

Actually when call this method it will start upload process & call uploadImageAsync method

uploadResult = async () =>  {
const { status } = await Permissions.askAsync(Permissions.CAMERA_ROLL);
const { onStartUpload } = this.props;
//if status not granted it will guide to grant permission from settings
if (status !== 'granted') {
if (Platform.OS === 'ios') this.showAlert();
return;
}
Expo.ImagePicker.launchImageLibraryAsync({
mediaTypes:'Images'
}).then((result)=>{
const file = result.uri;
if(!result.cancelled){
this.setState({
loading:true
})
uploadResponse = this.uploadImageAsync(result.uri).then((reponse)=>{
console.log(reponse,'reponse');
this.setState({
loading:false,
uploaded_photo:file
})
});
}
})
}

Initiate Upload image last process :
In this part of the code we have to define uri which we get from uploadResult method. Then need to provide
1. endpoint
2. payloadKey (ex: ‘file’ or ‘field_name’)
3. If restricted api provide appropriate header information on options.headers area

async uploadImageAsync(uri) {
const uriParts = uri.split('.');
const fileType = uriParts[uriParts.length - 1];
const { headers } = this.props;
const endpoint = this.state.endpoint; // Define Endpoint Here
const payloadKey = this.state.poayloadKey; // Define PayloadKey here Ex. 'file'
const method = 'POST';
const formData = new FormData();
formData.append(payloadKey, {
uri,
name: uid(),
type: `image/${fileType}`,
});
const options = {
method,
body: formData,
headers: {
Accept: 'application/json',
'Content-Type': 'multipart/form-data',
'Authorization': this.state.token, // If restricted provide appropriate token here otherwise ignore or remove this line
},
};
return fetch(endpoint, options);
}

So the final UploadImage.js is look like:

import React,{Component} from 'react';
import {
Text,
View,
Dimensions,
ActivityIndicator,
Platform,
Alert,
Linking,
StyleSheet,
Image,
TouchableOpacity,
} from 'react-native';
import { ImagePicker, Permissions } from 'expo';
import uid from 'uuid/v4';
export default class UploadImage extends Component{
constructor(props){
super(props)
this.askPermission = this.askPermission.bind(this);
this.showAlert = this.showAlert.bind(this);
this.state={
endpoint:this.props.endpoint?this.props.endpoint:null,
payloadKey:this.props.payloadKey? this.props.payloadKey:null,
token:this.props.token?this.props.token:null,
callbackUrl:this.props.callbackUrl?this.props.callbackUrl:null,
loading:false
}
defaultProps = {
onSuccess: undefined,
onFailure: undefined,
onStartUpload: undefined,
alertTitle: 'Please Allow Access',
alertMessage: [
'This applicaton needs access to your photo library to upload images.',
'\n\n',
'Please go to Settings of your device and grant permissions to Photos.',
].join(''),
alertNo: 'Not Now',
alertYes: 'Settings',
};
}
async askPermission() {
// only if user allows permission to camera roll
const { status } = await Permissions.askAsync(Permissions.CAMERA_ROLL);
const { onStartUpload } = this.props;
// On Android users are prompted every time,
// so no need to show additional Alert
if (status !== 'granted') {
if (Platform.OS === 'ios') this.showAlert();
return;
}
}
showAlert() {
const { alertMessage, alertTitle, alertYes, alertNo } = this.props;
Alert.alert(
'Please Allow Access',
[
'This applicaton needs access to your photo library to upload images.',
'\n\n',
'Please go to Settings of your device and grant permissions to Photos.',
].join(''),
[
{ text: 'Not Now', style: 'cancel' },
{ text: 'Settings', onPress: () => Linking.openURL('app-settings:') },
],
);
}
uploadResult = async () => {
const { status } = await Permissions.askAsync(Permissions.CAMERA_ROLL);
const { onStartUpload } = this.props;
console.log(status,'status');
if (status !== 'granted') {
if (Platform.OS === 'ios') this.showAlert();
return;
}
Expo.ImagePicker.launchImageLibraryAsync({
mediaTypes:'Images'
}).then((result)=>{
console.log(result,'result');
const file = result.uri;
if(!result.cancelled){
this.setState({
loading:true
})
uploadResponse = this.uploadImageAsync(result.uri).then((reponse)=>{
console.log(reponse,'reponse');
this.setState({
loading:false,
uploaded_photo:file
})
});
}
})
}
async uploadImageAsync(uri) {
const uriParts = uri.split('.');
const fileType = uriParts[uriParts.length - 1];
const { headers } = this.props;
const endpoint = this.state.endpoint; // Define Endpoint Here
const payloadKey = this.state.poayloadKey; // Define PayloadKey here Ex. 'file'
const method = 'POST';
const formData = new FormData();
formData.append(payloadKey, {
uri,
name: uid(),
type: `image/${fileType}`,
});
const options = {
method,
body: formData,
headers: {
Accept: 'application/json',
'Content-Type': 'multipart/form-data',
'Authorization': this.state.token, // If restricted provide appropriate token here otherwise ignore or remove this line
},
};
return fetch(endpoint, options);
}
render(){
if(this.state.loading){
return(
<View style={[style.container]}>
<ActivityIndicator size="large" color="#FF8241" />
</View>
)
}
return(
<View style={style.imgwrapper}>
{this.props.callbackUrl != null ? <Image source={{uri: this.state.uploaded_photo ? this.state.uploaded_photo : this.props.callbackUrl}} style={{width: 80, height: 80,borderRadius: 40}}/> : <Image source={{uri:'https://www.royaleboost.com/template/default-profile-img.png'}} style={{width: 80, height: 80}}/> }
<TouchableOpacity
style={style.circleWrapper}
onPress={()=>{
this.uploadResult();
}}
>
<View />
</TouchableOpacity>
</View>
)
}
}
const style = StyleSheet.create({
imgwrapper:{
justifyContent: 'center',
alignItems: 'center',
position:'relative',
marginBottom: 80,
},
circleWrapper:{
backgroundColor:'#ECECEC',
height:22,
width:22,
borderWidth:3,
borderColor: '#ffffff',
borderRadius:11,
marginLeft:70,
marginTop: -80,
},
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
})

Now you can add it to your desired component with four props

import UploadImage from 'src/libs/UploadImage';

Props list is given below-

payloadKey (Required) // field name
endpoint (Required) // Endpoint Url
callbackUrl (Optional) // Callback image url
token (Optional) // Restricted Api token
<UploadImage
payloadKey='file' // Field name
endpoint='https://www.api.com/upload' // url is fake replace with your own
callbackUrl={FetchedProfileImage} // CallBack Image url
token={this.state.tokenName} // Api Token if no restriction ignore it
/>

Like this you can use it to upload image on expo react native.
Hopefully it will help all you to gather basic mechanism of uploading image.

--

--