In this tutorial, learn how to use Expo Image Picker.
React Native provides built-in components that are standard building blocks used by every application, such as <View>
, <Text>
, and <Pressable>
.
We want to build a feature that isn't possible with these core components and API: selecting an image from the device's media library. For that, we will need a library.
To achieve this, we'll use an Expo SDK library called expo-image-picker
.
expo-image-picker
provides access to the system's UI to select images and videos from the phone's library or take a photo with the camera.
1
To install the library, run the following command:
-
npx expo install expo-image-picker
Tip: Any time we install a new library in our project, we must stop the development server by pressing Ctrl + c in the terminal and then running the installation command. After the installation, we can start the development server again by running
npx expo start
from the same terminal window.
2
expo-image-picker
provides the launchImageLibraryAsync()
method that displays the system UI for choosing an image or a video from the device's media library.
We can use the button with the primary theme we created in the previous chapter to pick an image from the device's media library. We'll create a function to launch the device's image library to implement this functionality.
In App.js, import the expo-image-picker
library and create a pickImageAsync()
function inside the App
component:
// ...rest of the import statements remain unchanged
import * as ImagePicker from 'expo-image-picker';
export default function App() {
const pickImageAsync = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
allowsEditing: true,
quality: 1,
});
if (!result.canceled) {
console.log(result);
} else {
alert('You did not select any image.');
}
};
// ...rest of the code remains same
}
Let's learn what the above code does.
launchImageLibraryAsync()
receives an object in which different options are specified.
This object is an ImagePickerOptions
object.
We can pass the object to specify different options when invoking the method.allowsEditing
is set to true
, the user can crop the image during the selection process on Android and iOS but not on the web.3
When the primary button gets pressed, we need to call the pickImageAsync()
function.
To call it, update the onPress
property of the <Button>
component in components/Button.js:
export default function Button({ label, theme, onPress}) {
// ...rest of the code remains same
if (theme === "primary") {
return (
<View>
{/* ...rest of the code remains same */}
<Pressable
style={[styles.button, { backgroundColor: '#fff' }]}
onPress={onPress}
>
</View>
);
}
}
In App.js, add the pickImageAsync()
function to the onPress
prop on the first <Button>
.
export default function App() {
// ...rest of the code remains same
return (
<View style={styles.container}>
{/* ...rest of the code remains same */}
<Button theme="primary" label="Choose a photo" onPress={pickImageAsync} />
</View>
);
}
The pickImageAsync()
function is responsible for invoking ImagePicker.launchImageLibraryAsync()
and then handling the result.
The launchImageLibraryAsync()
method returns an object containing information about the selected image.
To demonstrate what properties the result
object contains, here is an example result object:
{
"assets": [
{
"assetId": null,
"base64": null,
"duration": null,
"exif": null,
"height": 4800,
"rotation": null,
"type": "image",
"uri": "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%username%252Fsticker-smash-47-beta/ImagePicker/77c4e56f-4ccc-4c83-8634-fc376597b6fb.jpeg",
"width": 3200
}
],
"canceled": false,
"cancelled": false
}
4
The result
object provides the assets
array, which contains the uri
of the selected image.
Let's take this value from the image picker and use it to show the selected image in the app.
Modify the App.js file in the following steps:
selectedImage
using the useState
hook from React.
We'll use this state variable to hold the URI of the selected image.pickImageAsync()
function to save the image URI in the selectedImage
state variable.selectedImage
as a prop to the ImageViewer
component.import { useState } from 'react';
// ...rest of the import statements remain unchanged
export default function App() {
const [selectedImage, setSelectedImage] = useState(null);
const pickImageAsync = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
allowsEditing: true,
quality: 1,
});
if (!result.canceled) {
setSelectedImage(result.assets[0].uri);
} else {
alert('You did not select any image.');
}
};
return (
<View style={styles.container}>
<View style={styles.imageContainer}>
<ImageViewer
placeholderImageSource={PlaceholderImage}
selectedImage={selectedImage}
/>
</View>
{/* ...rest of the code remains same */}
</View>
);
}
Now, modify the components/ImageViewer.js file to conditionally display the selected image in place of the placeholder image.
We'll need to pass the selectedImage
prop to the component.
The source of the image is getting long, so let's also move it to a separate variable called imageSource
.
Then, pass it as the value of the source
prop on the <Image>
component.
export default function ImageViewer({ placeholderImageSource, selectedImage }) {
const imageSource = selectedImage ? { uri: selectedImage } : placeholderImageSource;
return <Image source={imageSource} style={styles.image} />;
}
In the above snippet, the <Image>
component uses a conditional operator to load the source of the image.
This is because the image picked from the image picker is a uri
string,
not a local asset like the placeholder image.
Let's take a look at our app now:
The images used for the demo in this tutorial were picked from Unsplash.
We added the functionality to pick an image from the device's media library.
In the next chapter, we'll learn how to create an emoji picker modal component.