How to load local dynamic images with html in React Native

First we will need to use react-native-render-html

(I like it because it doesn’t use WebView, and WebView for this kinda thing is bad.)

But there is a problem, this lib doesn’t have a way to load local images out of the box. For that** you need to create a custom image tag and add it to your HTML component**

Like this:

const htmlContent = ` 
  <h1>This HTML snippet is now rendered with native components !</h1>
  <img source="./src/assets/michael.jpg"/>
  <h2>Enjoy a webview-free and blazing fast application</h2>
  <em>Some random sentence!</em>
`;


        <HTML
          renderers={{
            img: (attribs) => {
              const imagePath = attribs.source;
              console.log(imagePath);
              return (
                <Image
                  key={attribs.source}
                  style={styles.imageContainer}
                  source={require('./src/assets/michael.jpg')}
                />
              );
            },
          }}
          source={{html: htmlContent}}
          contentWidth={contentWidth}
        />

Here i’m creating a custom tag named img inside renderers prop and defining it as an component with an image path that i have selected.

And that’s the result:

But the main problem isn’t solved, our goal is to render local images dynamically using that custom tag that we’ve created.

After this maybe you’re thinking:

-“Just pass the image path as a prop to the <img/> tag and voila, you’re done!”

OK, that sounds right, but how do I pass the image path that I want our custom tag to render?

I added a source prop with the image path in <img> tag.

<img source="./src/assets/michael.jpg"/>

And i am getting it inside our img function adding **attribs **as a parameter

Now i can access the image path using attribs.source

const htmlContent = ` 
  <h1>This HTML snippet is now rendered with native components !</h1>
  <img source="./src/assets/michael.jpg"/>
  <h2>Enjoy a webview-free and blazing fast application</h2>
  <em>Some random sentence!</em>
`;


        <HTML
          renderers={{
            img: (attribs) => {
              const imagePath = attribs.source;
              console.log(imagePath);
              return (
                <Image
                  key={attribs.source}
                  style={styles.imageContainer}
                  source={require('./src/assets/michael.jpg')}
                />
              );
            },
          }}
          source={{html: htmlContent}}
          contentWidth={contentWidth}
        />

This will output in the console:

"./src/assets/michael.jpg"

Now, if we try to change line 18 like this:

require('./src/assets/michael.jpg);

to

require(imagePath);

We are going to get this error:

[Error: TransformError App.js: App.js:Invalid call at line 31: require(imagePath)]

That’s because all the imports have to be a string, not a dynamic expression.

Maybe now you’re thinking:

“-If he is writing a post on Medium its because there’s is a way to import dynamic imports inside require, right?”

Well, no…

Let me show you what we are going to do:

One thing we know for sure, you can normally import images like this:

const imagesList = {
    dwight: require('./src/assets/dwight.jpg'),
    michael: require('./src/assets/michael.jpg)
  }

const htmlContent = ` 
  <h1>This HTML snippet is now rendered with native components !</h1>
  <img source="./src/assets/michael.jpg"/>
  <h2>Enjoy a webview-free and blazing fast application</h2>
  <em>Some random sentence!</em>
`;


        <HTML
          renderers={{
            img: (attribs) => {
              const imagePath = attribs.source;
              return (
                <Image
                  key={attribs.source}
                  style={styles.imageContainer}
                  source={imagesList[imagePath]}
                />
              );
            },
          }}
          source={{html: htmlContent}}
          contentWidth={contentWidth}
        />

So, i’m creating an object with all my images and it’s requires as properties of that object.

const imagesList = {
    dwight: require('./src/assets/dwight.jpg'),
    michael: require('./src/assets/michael.jpg)
  }

Now i can finally pass the image that we want to render in the source property in our custom tag.

<img source="michael"/>

We also need to modify the Image component to something like this:

<Image
   key={attribs.source}
   style={styles.imageContainer}
   source={imagesList[imagePath]}
 />

Now, if i change

<img source="michael"/>

to

<img source ="dwight"/>

Th will be the result:

Conclusion

The best way to implement this solution is to isolate your imageList variable in another file, and add each one of your images and it’s paths manually or you can create a script that does all the hard job for you (like i did).

You can learn how to create this script on this tutorial.

You can find the project source code here

I hope this has helped you ;)

21