72

I have read several posts about issues that people are having with React Native and the require() function when trying to require a dynamic resource such as:

Dynamic (fails):

urlName = "sampleData.json";
data = require('../' + urlName);

vs. Static (succeeds):

data = require('../sampleData.json');

I have read on some threads that this is a bug in React Native and in others that this is a feature.

Is there a new way to require a dynamic resource within a function?

Related Posts (all fairly old in React time):

11 Answers 11

45

React's require() only uses static url not variables, that means that you have to do require('/path/file'), take a look at this issue on github and this one for more alternative solutions, there are a couple of other ways to do it! for e.g

const images = {
profile: {
    profile: require('./profile/profile.png'),
    comments: require('./profile/comments.png'),
},
   image1: require('./image1.jpg'),
   image2: require('./image2.jpg'),
};

export default images;

then

import Images from './img/index';

render() {
    <Image source={Images.profile.comments} />
}

from this answer

Sign up to request clarification or add additional context in comments.

3 Comments

Well that sucks, I want to retrieve the image source from firebase and I can't do it dynamically. So now I have to use cloud storage and there goes my full offline support
Hey @MartínSchere did you found any other option beside using cloud storage? Now I'm facing same issue like yours, using import images one by one solution quite redundant for me..
@metalheadcoder there is no way around it, i just created a big json file for them
22

Here is my solution.

Setup

File structure:

app  
  |--src
    |--assets
      |--images
        |--logos
          |--small_kl_logo.png
          |--small_a1_logo.png
          |--small_kc_logo.png
          |--small_nv_logo.png
          |--small_other_logo.png

        |--index.js
    |--SearchableList.js

In index.js, I have this:

const images = {
  logos: {
    kl: require('./logos/small_kl_logo.png'),
    a1: require('./logos/small_a1_logo.png'),
    kc: require('./logos/small_kc_logo.png'),
    nv: require('./logos/small_nv_logo.png'),
    other: require('./logos/small_other_logo.png'),
  }
};

export default images;

In my SearchableList.js component, I then imported the Images component like this:

import Images from './assets/images';

I then created a new function imageSelect in my component:

imageSelect = network => {
  if (network === null) {
    return Images.logos.other;
  }

  const networkArray = {
    'KL': Images.logos.kl,
    'A1': Images.logos.a1,
    'KC': Images.logos.kc,
    'NV': Images.logos.nv,
    'Other': Images.logos.other,
  };

  return networkArray[network];
};

Then in my components render function I call this new imageSelect function to dynamically assign the desired Image based on the value in the this.state.network:

render() {
  <Image source={this.imageSelect(this.state.network)} />
}

The value passed into the imageSelect function could be any dynamic string. I just chose to have it set in the state first and then passed in.

I hope this answer helps. :)

2 Comments

Thanks! this is the best approach for multiple images. In my case, I had also to add '.default' at the end of 'require("..")'.
thank you brother, it helped me ! i forgot to add require inside the list of dictionaries images key's path
4

For anyone reading this that cannot work with the existing answers, I have an alternative.

First I'll explain my scenario. We have a mono repo with a number of packages (large react-native app). I want to dynamically import a bunch of locale files for i18n without having to keep a central registry in some magic file. There could be a number of teams working in the same monorepo and the DX we want is for package developers to be able to just add their local files in a known folder {{packageName}}/locales/en.json and have our core i18n functionality pick up their strings.

After several less than ideal solutions, I finally landed on https://github.com/kentcdodds/babel-plugin-preval as an ideal solution for us. This is how I did it:

const packageEnFiles = preval`
  const fs = require('fs');
  const path = require('path');

  const paths = [];

  const pathToPackages = path.join(__dirname, '../../../../packages/');
fs.readdirSync(pathToPackages)
    .filter(name => fs.lstatSync(path.join(pathToPackages, name)).isDirectory())
    .forEach(dir => {
      if (fs.readdirSync(path.join(pathToPackages, dir)).find(name => name === 'locales')) {
        const rawContents = fs.readFileSync(path.join(pathToPackages, dir, 'locales/en.json'), 'utf8');
        paths.push({
          name: dir,
          contents: JSON.parse(rawContents),
        });
      }
    });

  module.exports = paths;
`;

Then I can just iterate over this list and add the local files to i18next:

packageEnFiles.forEach(file => {
  i18n.addResourceBundle('en', file.name, file.contents);
});

2 Comments

Why not using i18next-fs-backend?
Because I don't have node available at runtime in a react-native app, but babel does at compile time.
4

I have found that a dynamic path for require() works when it starts with a static string. For example require("./" + path) works, whereas require(path) doesn't.

2 Comments

I've tried this before, it works like a charm in React (with CRA/Gatsby/NextJS), but not in React Native. Have you actually been able use this in React Native as well? Were there any other configurations like in jsconfig.json/tsconfig.json or babal.config.js?
Man, thank you so much, this one works for me! I'm on React though, not React Native
2

If you need to switch between multiple locally stored images, you can also use this way:

        var titleImg;
        var textColor;
        switch (this.props.data.title) {
        case 'Футбол':
            titleImg = require('../res/soccer.png');
            textColor = '#76a963';
            break;
        case 'Баскетбол':
            titleImg = require('../res/basketball.png');
            textColor = '#d47b19';
            break;
        case 'Хоккей':
            titleImg = require('../res/hockey.png');
            textColor = '#3381d0';
            break;
        case 'Теннис':
            titleImg = require('../res/tennis.png');
            textColor = '#d6b031';
            break;
        }

In this snippet I change variables titleImg and textColor depending of the prop. I have put this snippet directly in render() method.

Comments

1

Simple to dynamic images (using require)

Example array(into state)

this.state={
       newimage: require('../../../src/assets/group/kids_room.png'),
       randomImages=[
         {
            image:require('../../../src/assets/group/kids_room.png')
          },
         {
            image:require('../../../src/assets/group/kids_room2.png')
          }
        ,
         {
            image:require('../../../src/assets/group/kids_room3.png')
          }
        
        
        ]

}

Trigger image( like when press button(i select image random number betwenn 0-2))

let setImage=>(){

this.setState({newimage:this.state.randomImages[Math.floor(Math.random() * 3)];
})
}

view

<Image
        style={{  width: 30, height: 30 ,zIndex: 500 }}
        
        source={this.state.newimage}
      />

Comments

1

Hey lads I rounded another way to require It's ugly but works. Images dynamically. Instead of storing your URL in the state you store the entire JSX. For an example:

state = {
  image: []
};

Instead of

let imageURL = `'../assets/myImage.png'`
this.state.image = imageURL

You use

let greatImage = (<Image source={require(../assets/myImage.png)}></Image>)
this.state.image = greatImage

To render in the JSX

{this.state.image}

You can style your image in the variable too. I had to use some if statements to render some images dynamically and after break my head for 2 hours this was the way that solved my problem. Like I said It's ugly and probably wrong.

Comments

0

Try the solution mentioned in this thread for Android. This solves the issue but unfortunately, it's only for android.

But make sure to run react-native run-android after every update. Else, the added images won't appear in the app.

Comments

-1

Are you using a module bundler like webpack?

If so, you can try require.ensure()

See: https://webpack.js.org/guides/code-splitting/#dynamic-imports

2 Comments

What if you are using vanilla React Native without a module bundler?
I think RN uses the metro bundler which is what doesn't seem to support dynamic require().
-1

Reading through the docs, I've found a working answer and I'm able to use dynamic images, in the docs they refer to it as Network Images here

https://facebook.github.io/react-native/docs/images#network-images

Not sure if this can be applied to other file types, but as they list require with non image types

You would need to use the uri: call

data = {uri: urlName}

For me I got images working dynamically with this

<Image source={{uri: image}} />

Comments

-2

This seems to work :

const {
      messages,
    } = require(`../${dynamicPath}/messages.specific`);

1 Comment

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.