components images react native videos how to
Seamlessly Integrating Images and Videos into Your React Native Projects
Explore the effortless integration of images and videos into React Native projects with TwicPics Components, leveraging seamless lazy loading for optimal performance.
Miguel Beignon February 16, 2024 · 10 min read
Introduction
Integrating images and short videos into React Native projects can be a breeze!
In this step-by-step tutorial, we'll delve into the seamless process of incorporating compelling visual content using TwicPics Components.
We'll first showcase the simplicity of displaying an image while applying best practices: CLS optimization, LQIP, pixel-perfect, smart cropping, and ideal compression.
Once we've mastered this, we'll seamlessly extend our demonstration to highlight that displaying a short video is just as straightforward.
Incidentally, we'll see that, with TwicPics Components, lazy loading is out of the box. It is usable for both images and videos in any container, not just the constraining FlatList component.
Create your React Native project
Environnement
In this tutorial, we'll create a React Native application using Expo Go and run it on an iPhone 15 emulator running on macOS
.
You can, of course, achieve the same results using the React Native CLI, choosing an Android emulator, and working on another operating system.
Setup Wizard
Creating a React Native application using Expo Go Quickstart is as simple as:
# creates a new project using Expo Go Quickstart
yarn create expo-app AwesomeProject
Just follow the instructions and accept the installation requests. Once the project has been successfully created, you can cd
into its directory.
Start your application
To start the development server with Expo, use the following command:
# starts the development server
yarn start
If everything proceeds as expected, a QR code will be generated in the terminal. This QR code enables you to test your React Native application directly on your mobile device.
In this tutorial, we'll use our iPhone 15 emulator, which we launch by pressing the i
key.
And this is what we should get:
If something isn't working correctly here, we invite you to check the Expo Go documentation.
Install and configure TwicPics Components
Now that our React Native
application is up and running, it is time to install and configure the React Native version of the TwicPics components.
https://demo.twic.pics
If you don't have a TwicPics domain yet, you can easily create your own for free.
Install TwicPics Components
After stopping the development server, type the following to add the @twicpics/components package to your project.
As we plan to use the TwicVideo
component, we also need to install expo-av:
# using yarn
yarn add @twicpics/components
# only necessary if you intend to use `TwicVideo` component
yarn add expo-av@13.5.0
expo-av
in a React Native CLI app you must follow these
additional installation instructions.
Configure TwicPics Components
The configuration of the TwicPics components must be performed at the main entry point of the application.
In our case, modify the file app.js
as follows:
// app.js
/* imports TwicPics Components */
import { installTwicPics } from '@twicpics/components/react-native';
installTwicPics({
"domain": `https://demo.twic.pics/`, // set your very domain here
"debug": true, // this will output useful logs to the terminal
"maxDPR": 3, // set your desired maximum DPR here; default is 2
});
export default function App() {
/* file rest unchanged */
The setup is now complete, and that was the most intricate phase. We're now ready to showcase our images and videos.
Displaying Images with TwicPics Components
To display an image with TwicPics Components we just have to add TwicImg
component to the layout and set its src
attribute.
Here we display sea-anemone.jpg (jpeg
- 2400 x 1800 px - 761 kB).
Let's reopen app.js
and modify it as follows:
// app.js
import { StyleSheet, Text, View } from 'react-native';
import {
installTwicPics,
TwicImg, // import TwicImg
} from '@twicpics/components/react-native';
installTwicPics({
"domain": `https://demo.twic.pics/`,
"debug": true,
"maxDPR": 3,
});
export default function App() {
return (
<View style={styles.container}>
<TwicImg
src="sea-anemone.jpg" // image we want to display
/>
{/* testing CLS optimization */}
<Text>There is no CLS here.</Text>
</View>
);
}
/* file rest unchanged */
And this is what we should get now:
What happened here?
- As we haven't set a value for the ratio property, we get a square image.
- The display area has been reserved and there is no CLS.
- A Low-Quality Image Placeholder (LQIP) enhances the user experience.
An important point to note is that we haven't specified a display size for the image. Here, it spans the entire width of the viewport. Let's clarify this point with the following example.
The significance of the display context
Since TwicPics components are designed following the layout-driven pattern, it involves managing the size of their container.
Let's modify our app.js
file to display two variants of our master file. One has a size of 300px
, and the other has a size of 200px
. We achieve this by specifying a width
for the View
components encapsulating our TwicImg
elements:
// app.js
import { StyleSheet, Text, View } from 'react-native';
import { installTwicPics, TwicImg, } from '@twicpics/components/react-native';
installTwicPics({
"domain": `https://demo.twic.pics/`,
"debug": true,
"maxDPR": 4, // high value to test dpr awareness
});
export default function App() {
return (
<View style={styles.container}>
<View
style={{width: 300}} // constrains width to 300px
>
<TwicImg src="sea-anemone.jpg"/>
</View>
<Text style={styles.text}>There is no CLS here.</Text>
<View
style={{width: 200}} // constrains width to 200px
>
<TwicImg src="sea-anemone.jpg"/>
</View>
<Text>There is no CLS here either.</Text>
</View>
);
}
Here is the result of our modifications:
As shown in the console, using the same master file, we effectively get two different-sized images:
- https://demo.twic.pics/sea-anemone.jpg?twic=v1/cover=900x900
- https://demo.twic.pics/sea-anemone.jpg?twic=v1/cover=600x600
These results might seem surprising compared to the sizes we had specified (300x300 and 200x200, respectively). However, considering that the iPhone 15 has a DPR
of 3, these values make sense instead.
They showcase that TwicPics API has not only accurately provided variants matching the dimensions of the actual container but has also taken into account the actual pixel density. For short, TwicPics components are context-aware.
Lazy Loading without FlatList?
Implementing lazy loading in React Native
can be challenging, even with dedicated libraries.
A direct and simplified solution would be to use the FlatList component.
However, there again, it necessitates writing more cumbersome code.
With TwicPics Components, lazy loading requires no extra effort. It comes built-in, eliminating the need for manual implementation.
Let's display our images in both a vertical and horizontal scroll.
// app.js
import { ScrollView, StyleSheet, Text, View } from 'react-native';
import {
installTwicPics,
TwicImg
} from '@twicpics/components/react-native';
installTwicPics({
"domain": `https://demo.twic.pics/`,
"debug": true,
"maxDPR": 3,
});
// images to be displayed
const images = [
`clown-fish.jpg`,
`coral-reef.jpg`,
`sea-anemone.jpg`,
`sea-turtle.jpg`
];
export default function App() {
return (
<ScrollView>
<View style={styles.container}>
{ images.map( ( image, i ) => (
<View key={ i }>
<TwicImg
src={ image }
style={styles.img}
ratio="3/4" // displays an image with aspect ratio = 3/4
/>
</View>
) )
}
<Text>➡➡ An horizontal slider with lazy loaded images ➡➡</Text>
<ScrollView
horizontal
style={ styles.slider }
>
{ images.map( ( image, i ) => (
<View style={ styles.sliderItem } key={ i }>
<TwicImg
src={ image }
style={styles.img}
ratio="16/9" // displays an image with aspect ratio = 16/9
/>
</View>
) )
}
</ScrollView>
</View>
</ScrollView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
img: {
padding: 20,
},
slider: {
"marginHorizontal": 20,
},
sliderItem: {
width: 500,
},
});
You will note that in this example, we have specified a portrait
aspect ratio for the vertical scroll and 16:9
for the horizontal one.
This is what we should get now:
As highlighted in the console, images are loaded near or within the viewport, and lazy loading seamlessly operates for both vertical and horizontal scrolling situations.
As with previous examples, CLS is optimized, and LQIP enhances the user experience.
Intermission
We have seen how easy it is to efficiently and effortlessly display images in a React Native
project.
The next step of our journey will show that efficiently displaying short videos is no more complicated.
Displaying Short Videos with TwicPics Components
Let's revisit our initial example, but this time by using TwicVideo
component and jellyfish.mp4 (mp4
- 1920 x 1080 px - 10.30 Mb) as the video we want to showcase.
Our app.js
file becomes:
// app.js
import { StyleSheet, Text, View } from 'react-native';
import {
installTwicPics,
TwicVideo, // import TwicVideo
} from '@twicpics/components/react-native';
installTwicPics({
"domain": `https://demo.twic.pics/`,
"debug": true,
"maxDPR": 3,
});
export default function App() {
return (
<View style={styles.container}>
<TwicVideo
src="video/sea-anemone.mp4" // video we want to display
/>
{/* testing CLS optimization */}
<Text>There is no CLS here.</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
Here is the result:
Similarly to the image scenario:
- We get a square video as we haven't set a value for the ratio property.
- The display area has been reserved, and there is no CLS.
- A Low-Quality Image Placeholder (LQIP) enhances the user experience.
The Return of the Display Context
The layout-driven pattern also applies to videos, as demonstrated in the modified app.js
file below:
// app.js
import { StyleSheet, Text, View } from 'react-native';
import { installTwicPics, TwicVideo, } from '@twicpics/components/react-native';
installTwicPics({
"domain": `https://demo.twic.pics/`,
"debug": true,
"maxDPR": 4, // high value to test dpr awareness
});
export default function App() {
return (
<View style={styles.container}>
<View
style={{width: 300}} // constrains width to 300px
>
<TwicVideo src="video/jellyfish.mp4"/>
</View>
<Text style={styles.text}>There is still no CLS here.</Text>
<View
style={{width: 200}} // constrains width to 200px
>
<TwicVideo src="video/jellyfish.mp4"/>
</View>
<Text>Nor here either.</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
Again, using the same master file, we get two different variants, each fitting its container's size while considering the actual pixel density:
- https://demo.twic.pics/video/jellyfish.mp4?twic=v1/cover=900x900
- https://demo.twic.pics/video/jellyfish.mp4?twic=v1/cover=600x600
Lazy Loaded Videos?
Similarly to TwicImg
, lazy loading is seamlessly integrated into TwicVideo
, eliminating the need for manual and tedious implementation.
Let's demonstrate this by displaying a list of videos in portrait format (ratio="3/4"
) within a vertical ScrollView
and the same video list within a widescreen aspect ratio (ratio="16/9
) within a horizontal one.
import { ScrollView, StyleSheet, Text, View } from 'react-native';
import { installTwicPics, TwicVideo } from '@twicpics/components/react-native';
installTwicPics({
"domain": `https://demo.twic.pics/`,
"debug": true,
"maxDPR": 3,
});
// videos to be displayed
const videos = [
`turtle-swimming.mp4`,
`coral-reef.mp4`,
`sea-anemone.mp4`,
`jellyfish.mp4`
];
export default function App() {
return (
<ScrollView>
<View style={styles.container}>
{ videos.map( ( url, i ) => (
<View key={ i }>
<TwicVideo
src={ `video/${ url } ` }
style={ styles.item }
ratio="3/4" // displays video with aspect ratio = 3/4
/>
</View>
) )
}
<Text>➡➡ An horizontal slider with lazy loaded videos ➡➡</Text>
<ScrollView
horizontal
style={ styles.slider }
>
{ videos.map( ( url, i ) => (
<View style={ styles.sliderItem } key={ i }>
<TwicVideo
src={ `video/${ url } ` }
style={ styles.item }
ratio="16/9" // displays video with aspect ratio = 16/9
/>
</View>
) )
}
</ScrollView>
</View>
</ScrollView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
item: {
padding: 20,
},
slider: {
"marginHorizontal": 20,
},
sliderItem: {
width: 500,
},
});
This is the result on our device:
If we check the console, similarly to the case of images, our videos are effectively requested when they are in or approaching the viewport.
Appendix
For your reference, here is the list of media master files used in this tutorial.
Asset | Format | Dimensions | Size |
---|---|---|---|
clown-fish.jpg | JPEG | 2400 x 1548 px | 730 kB |
coral-reef.jpg | JPEG | 5963 x 3353 px | 2.10 MB |
sea-anemone.jpg | JPEG | 2400 x 1800 px | 761 kB |
sea-turtle.jpg | JPEG | 2395 x 2994 px | 964 kB |
turtle-swimming.mp4 | MP4 | 1920 x 1080 px | 31.85MB |
coral-reef.mp4 | MP4 | 1280 x 720 px | 3.66MB |
sea-anemone.mp4 | MP4 | 1920 x 1080 px | 8.16MB |
jellyfish.mp4 | MP4 | 1920 x 1080 px | 10.30MB |
Conclusion
Efficiently and effortlessly integrating images and short videos into a React Native
project is a breeze with TwicPics Components.
This tutorial briefly covered some essential aspects of these components, such as context awareness and integrated lazy loading.
With context awareness, automatic adaptation to various DPR, orientations, and viewport sizes is achieved from a single master file. This eliminates the need for complex technical adjustments, allowing developers to concentrate solely on templating.
Integrated lazy loading also eliminates technical difficulties. Combined with implementing LQIP (Low-Quality Image Placeholder), it ensures that media content loads seamlessly only when needed, optimizing overall performance and user experience.
If you want to explore more possibilities offered by TwicPics Components for React Native, please feel free to run the dedicated example project from its repository.
TwicPics Components are free, open-source, and available in various frameworks. The only requirement to use them is to have a TwicPics account. If you don't already have one, you can easily create your own TwicPics account for free.
Feel free to open an issue if you encounter any problems or have ideas for new features.