The built-in React Native
<Image /> component is feature-rich and provides many ways to improve page-load times. But keeping up with the best practices for responsive images requires spending lots of engineering hours making things just right.
Integrating imgix into your React Native workflow allows you to take advantage of the
<Image /> component's features while spending little time doing it.
Let's run through an example of how we can leverage imgix to speed up our app. At the end we'll have an image component that can:
- Resize an image automatically to fit the device dimensions
- Update image resolution automatically to match the device DPR
- "Blur-up" from an low-quality image placeholder (LQIP) to better serve low bandwidth users
Try toggling the Expo preview to see how the image loads at each step.
To integrate imgix into our application, we first need to create an account and upload our first image. Once we're set up, we can render our imgix image using the React Native (RN)
<Image /> component.
We'll start by setting our image URL as the
source URI on the Image component. We must also add a
height and some styles to our
<Image />. Otherwise, React Native won't know what size to render the image as.
Now we have an imgix image rendering in our App!
What if our user has a slow connection and we want to display something as it loads? Let's go ahead and add a background color to our image. This will give the user a sense of the dimensions of the image they're about to see as it loads.
Let's move on and start using imgix's Rendering API and
@imgix/js-core library to optimize our images, so they load fast. First, we need to install the package.
Then, we need to instantiate the client in our component. This will let us make use of its URL-building functions later.
Now, we can use it to resize the image to match our desired height. Our designers want a
950 px tall image for this page. We can pass this as an imgix rendering API parameter to the
Now our image will be automatically resized to match our set height value.
Still, we can do much better. Let's have the image automatically size itself to the window it's displayed in. This way, the image will be the right size on every device. We'll use React Native's
useWindowDimensions module to get the current window's dimensions.
Now that we can measure the device's dimensions, why not crop the image to match the device's height and width? This saves us lots of bytes and loads our image even faster. We can do this using the
fit: crop imgix rendering API parameter.
The image is resized and cropped to fit just right on any device automatically.
We still haven't accounted for one of the hardest things about working with images on mobile devices; device pixel ratio (DPR).
Mobile devices vary significantly in screen resolution, and images that look great on one can look terrible on the other if you fail to account for the differences in DPR.
Some developers try to get around this by compressing their images to fit the device resolution they plan to ship on. And their images look great until Apple or Google comes out with a new phone size or screen resolution that makes the images look terrible.
Our image will always be rendered with the correct DPR, ensuring it looks great on low- or high-resolution screens. The drawback here is that our image will be pretty heavy on high-resolution devices. A slower connection could lead to long load times and a "flash" of content.
We can get around this issue by storing two versions of this image, an LQIP and the full-resolution image. We will first load the LQIP and then load the full-resolution image once it's ready.
To do this, we'll create a low-resolution version of the image by setting the
h imgix parameters to be 1/4 of the full-size image width and height. We'll also add a
blur parameter so that the image doesn't look pixelated.
Note: the imgix rendering API has a
blurhashparameter. It yields a hash that can be used with a library like
react-native-blurhash. This is can be more performant but is incompatible with Expo Snacks.
Then we add the
lqipUri as the
source for our placeholder image.
Finally, we use some styling to absolutely position the images so that they render over one another.
Our low-resolution image will now render while our full-resolution image is still being requested.
But the transition is a little jarring. Let's add some animations to smoothly fade in from one image to the next, or "blur-up".
To do this, we'll use the React Native
Animated component and React's
useRef hook. We create a reference to the component's initial "transparent" state, and then, once the image has loaded,
onLoad , triggers a transition to a full opacity state.
Our image is looking great! Using imgix, our image now:
- resizes automatically to fit the device dimensions
- updates automatically to match the device DPR
- "blurs-up" to better serve low bandwidth users
The only thing left to do is clean things up and refactor our implementation into its own component,
We can now re-use this component across our application and take advantage of the imgix rendering API anywhere.
Using imgix with React Native is simple, reliable, and dynamic. It's an ideal solution for those who work with many images and want those images delivered in the appropriate format and size for all devices where they ship their app.
- js-core library: Check out the official docs for the
Responsive imagery is a rapidly-changing area of implementation, and different methods are applicable to different use cases. Here are our other tutorials that touch on aspects of responsive design.