React Native: require() with Dynamic String?

JavascriptReactjsReact NativeEcmascript 6Require

Javascript Problem Overview


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

Javascript Solutions


Solution 1 - Javascript

As i have heard of, 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

Solution 2 - Javascript

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. :)

Solution 3 - Javascript

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.

Solution 4 - Javascript

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

Solution 5 - Javascript

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.

Solution 6 - Javascript

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}
      />

Solution 7 - Javascript

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.

Solution 8 - Javascript

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

Solution 9 - Javascript

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}} />

Solution 10 - Javascript

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJake ChasanView Question on Stackoverflow
Solution 1 - JavascriptklendiView Answer on Stackoverflow
Solution 2 - JavascriptRyan SView Answer on Stackoverflow
Solution 3 - Javascriptph1lb4View Answer on Stackoverflow
Solution 4 - JavascriptBen SidelingerView Answer on Stackoverflow
Solution 5 - JavascriptDaniel ChernyshevView Answer on Stackoverflow
Solution 6 - JavascriptßãlãjîView Answer on Stackoverflow
Solution 7 - JavascriptGabriel SavianView Answer on Stackoverflow
Solution 8 - JavascriptkngrooView Answer on Stackoverflow
Solution 9 - JavascriptDaveClissoldView Answer on Stackoverflow
Solution 10 - JavascriptSuryaView Answer on Stackoverflow