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
Right, there's an easy solution here, I don't think this is actually a bug.
source={{ uri: imageName }}
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).
Question regarding the suggestion of @gavinsmith:
I was not aware you can do this for static image resources. What are the disadvantages of using { uri: "imageName" }
instead of require("image!imageName")
?
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.
@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" }} />
@satya164 I am not talking about images here.
React-native is using node.js, so i'm organising my code a bit like i do on server apps.
directory tree:
.
โโโ commonStyles.js
โโโ img
โย ย โโโ logo.png
โโโ network.js
โโโ storage.js
โโโ views
โโโ index.js
โโโ loading.js
โโโ login.js
โโโ profile.js
views/index.js
[
'loading',
'login',
'profile',
].forEach((file) => {
exports[file] = require('./' + file);
});
but have instead got to do:
exports.loading = require('./loading');
exports.login = require('./login');
exports.profile = require('./profile');
I am doing this so that whenever I require('./views')
i can reference any component without extra requires.
@matejkramny No, React Native doesn't use NodeJS.
If you've worked with client side apps and bundling JavaScript with webpack or browserify, that's how it works. The JavaScript files need to be statically analyzed in order to be bundled. You cannot use dynamic strings.
I see, got a bit confused as its got node_modules
, require
and all that.
Thanks for explaining
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?
@naji247 You've to put the files under the res/drawable like you'd add images in Android.
@satya164 but how to statically analyzed? There's no res/drawable directort
@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"}} />
@aicioara But what about iOS?
@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).
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.
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
[email protected]
[email protected]
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
Thats not really multiplatform solution. Is there any possible library or plugin which solves this for me?
same problem. how could I concat my variable to the image path... Is there any other solution?
Same issue as above. If React Native is designed this way, then how do you handle a situation where you do an API call and render a local image based on what you get back?
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];
}
@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]} />
@sahrens what if we have unknown number of images,, it can be 100 or 1000, we cant known the # of images at build time...
@vvavepacket Not sure what you use case would look like, but you might find the require-all module useful
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.
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} />
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 ;)
@RobIsHere Have you considered tackling this documentation issue yourself by submitting a PR? :-)
No. For me the best solution would be fixing the error message. "this error message is a bug". Probably someone who knows this code of Image source could do it in minutes. Docs is only plan B ;)
@sahrens I just wanted to give you a shout out and tell you that you are a gentleman and a scholar. Those who came here later in 2017 with this issue, that solution worked immediately for me.
Got a working solution, though not recommended for large images, works perfectly for (a lot of)small images.
Steps:
e.g.
ImageData.json
{
"icon1": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQ.......==",
"icon2": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQ.......=="
}
3.Import the json file to the place where you require the images dynamically.
e.g.
const imageData = require("./images/ImageData.json")
4: Get/generate the key/filename at runtime. and get the image source.
e.g.
const imageSrc = imageData[keyname]
5: Generate a image dynamically at runtime.
e.g.
<Image style={{ width: 70, height: 70, resizeMode: Image.resizeMode.contain }} source={ uri: imageSrc } />
Done..
Extra..
Written a helper python script to automate the json file creation.
import base64
import os
directory = os.fsencode('.')
with open('ImagesData.json', 'wb') as jsonFile:
jsonFile.write(bytes('{', 'utf-8'))
written = False
for file in os.listdir(directory):
filename = os.fsdecode(file)
if filename.endswith('.png'):
with open(filename, "rb") as image_file:
if written:
jsonFile.write(bytes(',\n','utf-8'))
encoded_string = base64.b64encode(image_file.read())
jsonFile.write(bytes(('"' +filename+ '":'), 'utf-8'))
jsonFile.write(bytes('"data:image/png;base64,', 'utf-8') + encoded_string + bytes('"', 'utf-8'))
written = True
jsonFile.write(bytes('}', 'utf-8'))
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
@sahrens Good idea! Thank you!
I attempted to use require
statements inside a JSON file but this fails. Converting the JSON to a .js
file and formatting it as above is the workaround I've now used.
https://stackoverflow.com/questions/51370371/dynamic-local-images-in-expo
Most helpful comment
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.