Skip to content

Instantly share code, notes, and snippets.

@muhozi
Created April 1, 2019 20:58
Show Gist options
  • Save muhozi/b5a498398c99f77cf3bfa4ef26f9617b to your computer and use it in GitHub Desktop.
Save muhozi/b5a498398c99f77cf3bfa4ef26f9617b to your computer and use it in GitHub Desktop.
React native image upload
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
TouchableOpacity,
Image,
FlatList,
AsyncStorage,
Dimensions,
ScrollView
} from 'react-native';
import ImagePicker from 'react-native-image-picker';
import firebase from 'react-native-firebase';
import uuid from 'uuid/v4'; // Import UUID to generate UUID
const options = {
title: 'Select Image',
storageOptions: {
skipBackup: true,
path: 'images'
}
};
const ImageRow = ({ image, windowWidth, popImage }) => (
<View>
<Image
source={{ uri: image }}
style={[styles.img, { width: windowWidth / 2 - 15 }]}
onError={popImage}
/>
</View>
);
export default class App extends Component {
state = {
imgSource: '',
uploading: false,
progress: 0,
images: []
};
componentDidMount() {
let images;
AsyncStorage.getItem('images')
.then(data => {
images = JSON.parse(data) || [];
this.setState({
images: images
});
})
.catch(error => {
console.log(error);
});
}
/**
* Select image method
*/
pickImage = () => {
ImagePicker.showImagePicker(options, response => {
if (response.didCancel) {
console.log('You cancelled image picker 😟');
} else if (response.error) {
alert('And error occured: ', response.error);
} else {
const source = { uri: response.uri };
this.setState({
imgSource: source,
imageUri: response.uri
});
}
});
};
/**
* Upload image method
*/
uploadImage = () => {
const ext = this.state.imageUri.split('.').pop(); // Extract image extension
const filename = `${uuid()}.${ext}`; // Generate unique name
this.setState({ uploading: true });
firebase
.storage()
.ref(`tutorials/images/${filename}`)
.putFile(this.state.imageUri)
.on(
firebase.storage.TaskEvent.STATE_CHANGED,
snapshot => {
let state = {};
state = {
...state,
progress: (snapshot.bytesTransferred / snapshot.totalBytes) * 100 // Calculate progress percentage
};
if (snapshot.state === firebase.storage.TaskState.SUCCESS) {
const allImages = this.state.images;
allImages.push(snapshot.downloadURL);
state = {
...state,
uploading: false,
imgSource: '',
imageUri: '',
progress: 0,
images: allImages
};
AsyncStorage.setItem('images', JSON.stringify(allImages));
}
this.setState(state);
},
error => {
unsubscribe();
alert('Sorry, Try again.');
}
);
};
/**
* Remove image from the state and persistance storage
*/
removeImage = imageIndex => {
let images = this.state.images;
images.pop(imageIndex);
this.setState({ images });
AsyncStorage.setItem('images', JSON.stringify(images));
};
render() {
const { uploading, imgSource, progress, images } = this.state;
const windowWidth = Dimensions.get('window').width;
const disabledStyle = uploading ? styles.disabledBtn : {};
const actionBtnStyles = [styles.btn, disabledStyle];
return (
<View>
<ScrollView>
<View style={styles.container}>
<TouchableOpacity
style={actionBtnStyles}
onPress={this.pickImage}
disabled={uploading}
>
<View>
<Text style={styles.btnTxt}>Pick image</Text>
</View>
</TouchableOpacity>
{/** Display selected image */}
{imgSource !== '' && (
<View>
<Image source={imgSource} style={styles.image} />
{uploading && (
<View
style={[styles.progressBar, { width: `${progress}%` }]}
/>
)}
<TouchableOpacity
style={actionBtnStyles}
onPress={this.uploadImage}
disabled={uploading}
>
<View>
{uploading ? (
<Text style={styles.btnTxt}>Uploading ...</Text>
) : (
<Text style={styles.btnTxt}>Upload image</Text>
)}
</View>
</TouchableOpacity>
</View>
)}
<View>
<Text
style={{
fontWeight: '600',
paddingTop: 20,
alignSelf: 'center'
}}
>
{images.length > 0
? 'Your uploaded images'
: 'There is no image you uploaded'}
</Text>
</View>
<FlatList
numColumns={2}
style={{ marginTop: 20 }}
data={images}
renderItem={({ item: image, index }) => (
<ImageRow
windowWidth={windowWidth}
image={image}
popImage={() => this.removeImage(index)}
/>
)}
keyExtractor={index => index}
/>
</View>
</ScrollView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
backgroundColor: '#ffffff',
marginTop: 20,
paddingLeft: 5,
paddingRight: 5
},
btn: {
paddingLeft: 20,
paddingRight: 20,
paddingTop: 10,
paddingBottom: 10,
borderRadius: 20,
backgroundColor: 'rgb(3, 154, 229)',
marginTop: 20,
alignItems: 'center'
},
disabledBtn: {
backgroundColor: 'rgba(3,155,229,0.5)'
},
btnTxt: {
color: '#fff'
},
image: {
marginTop: 20,
minWidth: 200,
height: 200,
resizeMode: 'contain',
backgroundColor: '#ccc',
},
img: {
flex: 1,
height: 100,
margin: 5,
resizeMode: 'contain',
borderWidth: 1,
borderColor: '#eee',
backgroundColor: '#ccc'
},
progressBar: {
backgroundColor: 'rgb(3, 154, 229)',
height: 3,
shadowColor: '#000',
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment