DEV Community

loading...

How to load local dynamic images with html in React Native

Everaldo Junior
Building awesome stuff
・3 min read

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}
        />
Enter fullscreen mode Exit fullscreen mode

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"/>
Enter fullscreen mode Exit fullscreen mode

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}
        />
Enter fullscreen mode Exit fullscreen mode

This will output in the console:

"./src/assets/michael.jpg"
Enter fullscreen mode Exit fullscreen mode

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

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

to

require(imagePath);
Enter fullscreen mode Exit fullscreen mode

We are going to get this error:

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

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}
        />
Enter fullscreen mode Exit fullscreen mode

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)
  }
Enter fullscreen mode Exit fullscreen mode

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

<img source="michael"/>
Enter fullscreen mode Exit fullscreen mode

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

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

Now, if i change

<img source="michael"/>

to

<img source ="dwight"/> 
Enter fullscreen mode Exit fullscreen mode

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 ;)

Discussion (0)