react-native: Setting source with string concatenation fails ('Requiring unknown module...')

I’ve seen this mentioned before: https://github.com/facebook/react-native/issues/282#issuecomment-96908438

I’m trying to include an image from within the project, the name of which is dependant on variables.

var imageName = `image!${var1}_of_${var2}`
contents = (
  <Image source={require(imageName)} style={styles.card} onPress={this._onPress} />
)

The above fails with the usual:

Requiring unknown module “image!somwething_for_somethingelse”. If you are sure the module is there, try restarting the packager.

These also fail in the same manner:

<Image source={require(image!${var1}of${var2})}> <Image source={require('image!' + {var1} + '_of_' + {var2})} >

This works, no problem:

<Image source={require('image!somwething_for_somethingelse')}>

I’ve also tried

  • Stop and re-build Xcode project
  • Restarting the packager

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Reactions: 20
  • Comments: 31 (9 by maintainers)

Commits related to this issue

Most upvoted comments

this ‘feature’ is retarded and is annoying. Would very much be interested how i can bypass this stupid check

WHILE i agree that it is a good idea to stop developers from including images which consist of concatenated strings, it is the developer’s responsibility to code in such way that won’t cause him trouble in the future. A much better solution for react-native would be to print a notice to the console alerting them of what they just done.

We intentionally don’t support dynamically generated image names because it makes it very hard to manage assets over time, just like how you wouldn’t want to do

var MyComponent = require(‘./’ + libName + typeOfComponent);

or something like that. Dynamic image name generation like this also won’t work with the new dynamic asset managing system we’re rolling out which let’s you add and update assets on the fly with just cmd+R (no more need to add to Xcode and recompile).

You must enumerate the local images, like

const IMAGES = {
  image1: require('../image1'), // statically analyzed
  image2: require('../image2'), // statically analyzed
}

getImage(num: number) { // dynamically invoked
  return IMAGES['image' + num];
}

Right, there’s an easy solution here, I don’t think this is actually a bug.

source={{ uri: imageName }}

For now I’m defining a thumbnails object in a constants file:

export const thumbnails = {
  'orange'  : require('../assets/thumb-orange.png'),
  'blue'    : require('../assets/thumb-blue.png'),
  'teal'    : require('../assets/thumb-teal.png')
}

Then I import that object into my component. During the render() call, I’m doing:

const thumbnail = thumbnails[this.props.color]
<Image source={thumbnail} />

@nollydeng The folder drawable must be created under the already existing android/app/src/main/res. Add a file such as

android/app/src/main/res/drawable/myImage.png

and reference it in code as

<Image source={{uri: "myImage"}} />

If you don’t know how many there are, then they can’t be local static assets installed with the APK. At the very least, you can codegen a file with all the requires. If you are loading images off the network, then just set the source uri property like normal.

I got working solution for this it may be helpfull Just put the images URI or file location in array like this

  Nav_items:[{sourcess:require('../icons/s.png'),names:'Home'},
            {sourcess:require('../icons/s.png'),names:'Deals'},{sourcess:require('../icons/s.png'),names:'fashion'},
            {**sourcess:require('../icons/s.png')**,names:'mobile & accessories'},
            {sourcess:require('../icons/s.png'),names:'kitchen and dining'},
            {sourcess:require('../icons/s.png'),names:'Home,tools & decor'},
            {sourcess:require('../icons/s.png'),names:'sports & fitness'},
            {sourcess:require('../icons/s.png'),names:'computer & software'}
            ,{sourcess:require('../icons/s.png'),names:'Baby & toys'},
            {sourcess:require('../icons/s.png'),names:'Perfumes & Beauty'},
            {sourcess:require('../icons/s.png'),names:'CAMERAS'},
            {sourcess:require('../icons/s.png'),names:'Track order'}
            ,{sourcess:require('../icons/s.png'),names:'my account'}
            ,{sourcess:'../icons/s.png',names:'new feed'}
        ,{sourcess:require('../icons/s.png'),names:'wishlist'}],

Then refer the image as like

<List dataArray={this.state.Nav_itemss}
            renderRow={(item) =>
              <ListItem>
                  <View style={{flexDirection:'row'}}>
                  **<Image style={{width:35,height:25}} 
                  resizeMode="center"
                  source={item.sourcess}/>**
                <Text>{item.names}</Text>                
                    </View>
              </ListItem>
            }>
          </List>

I am using a list to feed my navigation drawer item its working fine for me

Thats not really multiplatform solution. Is there any possible library or plugin which solves this for me?

@dasmikko For iOS you need to include them as an asset, eg by placing them in your project much the same as you would a custom font or any other file. From that point on you can refer to the image by its exact filename (for iOS, including the extension, for Android, without).

Usage

So your image tag could be generically used as follows:

import { Platform, Image } from 'react-native

// ...

// render fn returns:
<Image source={{ uri: `filename${Platform.OS === 'ios' ? '.jpg' : ''}` }} />

For your convenience it might be worth making a quick wrapper around Image, call it something like ManuallyBundledImage (bad name, I know), and use that instead for the images you include manually.

Pixel density variants

iOS

iOS will automatically use @2x and @3x variants if you append that to their filenames. You do not need to change the uri in the image tag – it should automatically grab the proper pixel density based on device:

// images to add to Xcode:
filename.jpg
filename@2x.jpg
filename@3x.jpg

Android

For android, you can use variants for pixel densities by placing ldpi, mdpi, hdpi, xhdpi, etc variants in the proper folders as follows:

android/app/src/main/res/drawable/filename.jpg // default fallback image
android/app/src/main/res/drawable-ldpi/filename.jpg // different resolution
... // other dpi variants
android/app/src/main/res/drawable-xxxhdpi/filename.jpg // different resolution

@naji247 You’ve to put the files under the res/drawable like you’d add images in Android.

@matejkramny

The images need to be able to statically analyzed, so that the packager could resolve them and package in the app automatically. Hence dynamic strings with require syntax is not possible.

It’s the same as bundling JavaScript with browserify or webpack. Your JavaScript filenames need to be statically analyzed and bundled.

If you want to use dynamic strings, you sure can. But you’ve to manually package up the assets. You can use the following syntax.

<Image source={{ uri: "image" + "name" }} />

@sahrens, thanks! This worked perfectly for me.

In my component, I imported my equivalent of your IMAGES and used it in my Image element:

<Image source={IMAGES[image.key]} />

@RobIsHere Have you considered tackling this documentation issue yourself by submitting a PR? 😃

Hey guys, I’m trying to use the manual versions of this using source={{uri: "imagename"}} but it’s not finding my files that in the same directory as the component rendering them… How should my files be organized/ where should they be in order for this to work?

The error message “Unknown named module” is totally misleading!!! For me this error message is a bug.

Please add this to docs at https://facebook.github.io/react-native/docs/image.html

An Explanation with example like the following one on stack overflow and @satya164 's good explanation about the static analysis for packaging requirement + best practise https://stackoverflow.com/questions/38776713/react-native-image-component-requiring-unknown-module

It’s not something you would expect to happen (I haven’t seen 32 and 56 thumbs down very often). But you have a perfect reason for doing it like this. So please don’t let the people in the dark - this issue has been opened mid 2015 and is still visited 😉

@aicioara But what about iOS?