React Native Image Performance

For the second installment of this React Native performance series lets look at images. Over the past few months I’ve learned a lot about what works and what doesn’t work when it comes to working with images in a react native project. For most projects, hitting performance issues related to images is unlikely. Either way it is good to know what to watch out for and keep your project on the right path to avoid them in the future.

Loading Static Assets

With static assets I’ve found noticeable performance gains by simply loading assets from the app package (images included via Xcode asset catalogs or in the Android drawable folder) vs the JavaScript package. I found this while trying to load 350 icon assets in the same view (very uncommon). I was seeing nearly a 15 second render time for the view when loading the assets from the JavaScript package. Once I moved all the assets to the app package my render time went down to 10 milliseconds. When loading assets from the Javascript package, React Native requires the asset file from the package and then sends it across the bridge to the UI Layer to be rendered. When the asset is already within the app package, React can just tell the UI layer to render the specific image without having to require or transfer the image data across the bridge.

Include assets in iOS app package

You can either use the existing asset catalog that comes with the base Xcode project (Images.xcassets) or create a new one. To create a new one, in your Xcode project go to File -> New -> File -> Asset Catalog (in the Resource section), name it whatever you would like. Once the new asset catalog is added to your project make sure it is included in your Build Phases -> Copy Bundle Resources.

To add your static asset images, simply click on your asset catalog in Xcode and drag your asset files into it. Or once the asset catalog is open in Xcode, you can use the plus button in the lower left hand corner to add assets.

Now in your javascript, simply set the source uri string to the file name of your image (without file extension). It is important to specify a width and height or else your image wont render.

style={{height: 20, width: 20}}
source={{uri: 'my_cool_icon'}} // Don't include file extension

Include assets in Android app package

Add your static asset images to the drawable folder of the android project (android/app/src/main/res/drawable). Keep this folder single level, anything placed in subdirectories android wont see. Make sure every file name starts with a letter or you will get an error when compiling the project.

Similar to iOS, in your javascript simply set the source uri string to the file name (without file extension). For some reason on android I have to specify a width and height directly on the image component to get the image to render. Not sure if this is a bug or just undocumented. If you look at the react native docs for the Image component it doesn’t even show support for these props.

style={{height: 20, width: 20}}
source={{uri: 'my_cool_icon'}} // Don't include file extension

Loading Remote Assets

Unless your app is heavily based around loading images from remote endpoints, you probably don’t want to implement your own image caching system. For us at WeDo we didn’t see this as necessarily a performance reasons, rather ethically something we should do for our users. There is no reason why our app should be wasting our users data downloading remote assets on every launch it can easily cache. One advantage of this is once the assets are indeed cached client side, load time for our views will be that much quicker.

Luckily, React Native Fast Image is a great package that can do this for us. It’s super easy to use as well. You can pretty much just include the package and switch out the Image component for the FastImage component. Fast Image will deal with all the client side caching for you.

style={{height: 250, width: 250}}
source={{uri: ''}}

Asset File Type and Size

When working with assets in react native you should take a similar approach as you would on the web. We want to use the smaller file size as possible. When we are loading assets from the JavaScript package those files are being sent across the bridge. So the larger those files are the longer it’s going to take for them to transfer across and be rendered on the screen. To achieve the smallest file size I do a few things. When possible I use JPEG files. They will naturally be a smaller file size as they can be compressed down further. Unfortunately with a lot of UI stuff you need transparency so you have no choice but to use PNG.

I push all my assets for a project through ImageOptim. This nifty little app will compress the images down to their smallest possible file size. This won’t necessarily produce the biggest performance gains, but is a good rule of thumb for any project.

Icon design by Chameleon Design from the Noun Project

Looking for more Performance Tips and Tricks?

React Native Performance

A collection of tips and tricks to solve common performance issue with React Native apps.

Use promo code medium for 10% off!

Download React Native Performance Book —