Code Buckets

Buckets of code

React Native

Working with Dynamic Images in React Native

I’ve been recently developing mobile apps using React Native and TypeScript and here’s an odd thing – it’s not actually possible to use dynamic images within React Native.

The Problem with Dynamic Images

I’ve coded an Android app that displays quotes. If I swipe left and right it changes quotes – nice. If I swipe up and down I want it to change background image. When the the app loads it looks like this…

Buddhist quote app
Relaxing quote and image

And when I swipe up I want it to change the background image to this…

Buddhist quote with dynamic image
I’ve swiped up so the background has changed.

There are 10 images in total and it will cycle through them all – background1.jpg through to background10,.jpg then starting again at background1.jpg 

All dynamic images
My images for the app as show in VS Code

In every other programming framework I’ve worked with, the obvious thing to do is to construct the image name and path dynamically and load it into the UI. In React Native this would be

const backgroundImage = require(`background${imageNumber}.jpg`);

  return (
    <ImageBackground source={backgroundImage} style={styles.container}>
      {children}
    </ImageBackground>
  );

But if I do this, then I get this error in my app.

Dynamic image error
Alarming error

Dynamic images are a problem.

The Solution

React Native doesn’t deal with dynamic images, only static images. Therefore, you have to front up all the images – you cannot construct the name and path dynamically. 

The solution I’ve employed is to hide the dirty details in a static class like so

interface Image {
  name: string;
  image: any;
}

export class BackgroundImage {
  private static images: Array<Image> = [
    {
      name: 'background1.jpg',
      image: require('../assets/images/background1.jpg'),
    },
    {
      name: 'background2.jpg',
      image: require('../assets/images/background2.jpg'),
    },
    {
      name: 'background3.jpg',
      image: require('../assets/images/background3.jpg'),
    },
    {
      name: 'background4.jpg',
      image: require('../assets/images/background4.jpg'),
    },
    {
      name: 'background5.jpg',
      image: require('../assets/images/background5.jpg'),
    },
    {
      name: 'background6.jpg',
      image: require('../assets/images/background6.jpg'),
    },
    {
      name: 'background7.jpg',
      image: require('../assets/images/background7.jpg'),
    },
    {
      name: 'background8.jpg',
      image: require('../assets/images/background8.jpg'),
    },
    {
      name: 'background9.jpg',
      image: require('../assets/images/background9.jpg'),
    },
    {
      name: 'background10.jpg',
      image: require('../assets/images/background10.jpg'),
    },
  ];

  static GetImage = (name: string) => {
    const found = BackgroundImage.images.find(e => e.name === name);
    return found ? found.image : null;
  };
}

And now I can call it in my components thus

 const backgroundImage = BackgroundImageService.GetImage(
    `background${imageNumber}.jpg`,
  );

  return (
    <ImageBackground source={backgroundImage} style={styles.container}>
      {children}
    </ImageBackground>
  );

Rather than constructing the image name dynamically which is disallow, I’m constructing a key to an array in which the images are statically loaded. This is allowed, and the call is very similar to how I wanted to call it in the first place – except this time it actually works.

Possible Extensions

The BackgroundImage class is basically boilerplate – the only thing that would change is the image array. I can imagine a world where there is a node tool which will read all the image files in a given directory and generate the class needed to access them i.e. it will autogenerate a class like the BackgroundImage class. 

If it doesn’t already exist then it might be a nice side project to put one up.

The Code

As ever, the code for the quotes application is on my GitHub site at

https://github.com/timbrownls20/buddha-quotes-mobile

And the BackgroundImage class is at

https://github.com/timbrownls20/buddha-quotes-mobile/blob/main/services/BackgroundImage.ts

The incorrect implementation of dynamic image referencing is published in a branch, so you can see what not to do 

https://github.com/timbrownls20/buddha-quotes-mobile/tree/dynamic-images-incorrect-implementation

The quotes mobile app isn’t live yet so no link in Google Play, but I aim to publish in the next few weeks / months depending on other commitments and general personal energy levels.

Useful Links

https://reactnative.dev/
React Native homepage. It’s by no means the ony JavaScript framework for developing mobile apps but it’s a popular one and I’m enjoying it.

https://reactnative.dev/docs/images#static-image-resources
A full explanation of why React Native needs static resources. Broadly speaking, it’s because the bundler uses the static strings to identify and correctly process all the assets. React Native is such a clever framework, I really don’t mind these kind of odd implementation details. I’m writing iOS and Android apps in JavaScript which is super great so I’m happy to suck these kind of things up.

https://codebuckets.com/2021/10/22/buddhist-texts-api-dhammapada/
The quotes in the app are Buddha quotes, specifically from the Dhammapada. I’m using the Buddhist texts API that I maintain, to obtain the quotes. The mobile app is a variant of the infinite Buddha quotes website I did late last year. The mobile app has clearly got more swipes and taps and will be generally better and more exciting.

1 COMMENTS

  1. Thanks for showing this in Typescript!
    I’m curious if there is a better way that using type = any for the image urls though?

LEAVE A RESPONSE

Your email address will not be published. Required fields are marked *