When learning React Native, we find that majority of issues are encountered while trying to implement features such as taking a picture, accessing photos from the mobile device, chats, authentication, etc. These issues are a bit hard to resolve as the React Native documentation does not explain these concepts very well. Thus, we have to use libraries to achieve any of the above functionalities.
In this guide, we will highlight the features implemented using React Native APIs. This guide will help you implement the camera roll API for accessing pictures on a device. Feel free to also check out the official React Native documentation.
For someone just starting to build React Native apps, this should be a fairly simple guide to get started with. We'll be building our app for IOS, so the setup is according to that platform. We can go to the React Native site and follow the steps to build projects with native code.
Also for a quick setup, we can use the create-react-native-app.
By now, the app should be up and running on either the emulator or iPhone device. Below is how the folder structure should look. We have a component folder with three components as below:
CamScreen.js - The add picture button and accessing the camera roll take place here.
ViewPictures.js - Displays pictures from your iPhone.
We have the boilerplate code in our index.ios.js. It should look something like this:
1import React, { Component } from 'react';
2import {
3 AppRegistry,
4 StyleSheet,
5 Text,
6 View
7} from 'react-native';
8import CamScreen from './component/CamScreen';
9
10export default class camRollExample extends Component {
11 render() {
12 return (
13 <CamScreen/>
14 );
15 }
16}
17
18AppRegistry.registerComponent('camRollExample', () => camRollExample);
In CamScreen.js, we have a simple interface where we have the add picture button, and we also import the CameraRoll module from React Native.
1import React, { Component } from 'react';
2import {
3 CameraRoll,
4 Image,
5 StyleSheet,
6 TouchableHighlight,
7 View,
8} from 'react-native';
9
10class CamScreen extends Component {
11
12 render() {
13 return (
14 <View style={styles.container}>
15 <TouchableHighlight>
16 <Image
17 source={require('../assets/addPicture.png')} />
18 </TouchableHighlight>
19 </View>
20 );
21 }
22}
23
24const styles = StyleSheet.create({
25 container: {
26 flex: 1,
27 justifyContent: 'center',
28 alignItems: 'center'
29 }
30});
31
32export default CamScreen;
For accessing photos, we need a click event. Let's add the onPress
prop to the button and a handler method called getPicturesFromGallery()
.
1//...
2render() {
3 return (
4 <View style={styles.container}>
5 <TouchableHighlight
6 onPress={() => this.getPicturesFromGallery()}>
7 <Image
8 source={require('../assets/addPicture.png')} />
9 </TouchableHighlight>
10 </View>
11 );
12}
1//...
2 getPicturesFromGallery() {
3 CameraRoll.getPhotos({ first: 5000 })
4 .then(res => {
5 console.log(res, "images data")
6 })
7 }
8 //...
The object inside the getPhotos({ first: 5000 })
is used to specify the number of images that we want to get from the gallery. When we run the app, we'll encounter an error:
"Cannot read property 'getPhotos' of undefined"
The above error happens because the camera roll library has not been added or linked to our build phases in Xcode. To fix the error, we'll:
Go to our project directory
Open IOS directory
Navigate to the file that has .xcodeproj as the extension. In our case, it should be camRollExample.xcodeproj
Next, we should drag RCTCamRoll.xcodeproj in our project directory to Xcode.
Let's drag the RCTCamRoll.xcodeproj file to libraries file in Xcode. We can then click on Build Phases located in the top right-hand corner in Xcode. Let's click the dropdown next to Link Binary With Libraries, then the + sign to add libRCTCamRoll.a.
We can then run the build and restart our emulator or device. The image object should be visible in our log. To check the images, we need to have the uri in the image object. Here is an updated version of CameraRoll.js.
1//...
2import ViewPictures from './ViewPictures';
3
4class CamScreen extends Component {
5
6 state = {
7 showPhotoGallery: false,
8 pictureArray: []
9 }
10
11 getPicturesFromGallery() {
12 CameraRoll.getPhotos({ first: 5000})
13 .then(res => {
14 let pictureArray = res.edges;
15 this.setState({ showPhotoGallery: true, pictureArray: pictureArray })
16 })
17 }
18
19 render() {
20 if (this.state.showPhotoGallery) {
21 return (
22 <ViewPictures
23 pictureArray={this.state.pictureArray} />
24 )
25 }
26 return (
27 <View style={styles.container}>
28
29 <TouchableHighlight
30 onPress={() => this.getPicturesFromGallery()}>
31 <Image
32 source={require('../assets/addPicture.png')} />
33 </TouchableHighlight>
34 </View>
35 );
36 }
37}
38//...
In the above code snippets, we just imported ViewPictures.js. This is for displaying the images inside of a list view.
1import React, { Component } from 'react';
2import {
3 Image,
4 View,
5 ListView,
6 StyleSheet,
7 Text,
8 TouchableHighlight
9
10} from 'react-native';
11
12import SelectedPicture from './SelectedPicture';
13
14class ViewPictures extends Component {
15 state = {
16 ds: new ListView.DataSource({
17 rowHasChanged: (r1, r2) => r1 !== r2
18 }),
19 showSelectedPicture: false,
20 uri: ''
21 }
22
23 renderRow(rowData) {
24 const { uri } = rowData.node.image;
25 return (
26 <TouchableHighlight
27 onPress={() => this.setState({ showSelectedPicture: true, uri: uri })}>
28 <Image
29 source={{ uri: rowData.node.image.uri }}
30 style={styles.image} />
31 </TouchableHighlight>
32 )
33 }
34
35 render() {
36 const { showSelectedPicture, uri } = this.state;
37
38 if (showSelectedPicture) {
39 return (
40 <SelectedPicture
41 uri={uri} />
42 )
43 }
44 return (
45 <View style={{ flex: 1 }}>
46 <View style={{ alignItems: 'center', marginTop: 15 }}>
47 <Text style={{ fontSize: 30, fontWeight: '700' }}>Pick A Picture !</Text>
48 </View>
49 <ListView
50 contentContainerStyle={styles.list}
51 dataSource={this.state.ds.cloneWithRows(this.props.pictureArray)}
52 renderRow={(rowData) => this.renderRow(rowData)}
53 enableEmptySections={true} />
54 </View>
55 );
56 }
57}
58
59const styles = StyleSheet.create({
60 list: {
61 flexDirection: 'row',
62 flexWrap: 'wrap'
63 },
64
65 image: {
66 width: 120,
67 height: 130,
68 marginLeft: 15,
69 marginTop: 15,
70 borderRadius: 6,
71 borderWidth: 2,
72 borderColor: '#efefef'
73 }
74})
75
76export default ViewPictures;
When we click or select a picture from the list, the selected picture will get displayed in the SelectedPicture.js component.
1import React from 'react';
2import {
3 Image,
4 View,
5 StyleSheet,
6 Text,
7 TouchableHighlight
8} from 'react-native';
9
10const SelectedPicture = (props) => {
11 const { uri } = props;
12 return (
13 <View style={styles.container}>
14 <Image
15 source={{uri: uri}}
16 style={styles.image}/>
17 </View>
18 );
19};
20
21const styles = StyleSheet.create({
22 container: {
23 flex: 1,
24 justifyContent: 'center',
25 alignItems: 'center'
26 },
27 image: {
28 height: 300,
29 width: 200
30 }
31});
32
33export default SelectedPicture;
Having run the app on both iPhone 6s and iPhone 6s plus, we can extend the test to other devices and verify how it performs on other platforms.