React Native: require() with Dynamic String? React Native: require() with Dynamic String? javascript javascript

React Native: require() with Dynamic String?


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


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


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