19

I've component in my application which works fine if it is assigned direct string value("someImage.png"), but if I try to assign it by storing image name in a local variable it gives this exception "require() must have a single string literal argument" This line works fine

<ImageBackground source={require("./Resources/bg/imageone.png")} resizeMode='cover' style={customStyles.backdrop}>

Issue occurs in this case

let imageName = "./Resources/bg/imageone.png";          
<ImageBackground id="123" source={require(imageName)} resizeMode='cover' style={customStyles.backdrop}>

I also found same issue reported here, but no one has answered that yet. Can you help me out here?

5 Answers 5

20

This example of dynamic images can also show how to correctly assign a variable with the image source value. The recommendation is to assign the whole require in a variable, instead of just its value.

// GOOD
<Image source={require('./my-icon.png')} />;

// BAD
var icon = this.props.active ? 'my-icon-active' : 'my-icon-inactive';
<Image source={require('./' + icon + '.png')} />;

// GOOD
var icon = this.props.active
  ? require('./my-icon-active.png')
  : require('./my-icon-inactive.png');
<Image source={icon} />;

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

Hope it helps

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

8 Comments

You could also look at this issue on Github.
@soutot it works, but I think react-native should really add support to accept variable in require(), what if document path is vary large, this could easily introduce typing mistakes and change would cost more time.
What if the image name is totally dynamic and being passed in props? How will we render that?
@Picci if you have different icons, you should store the whole require in a variable, as the example above shows under // GOOD comment line. @MuhammadHannan that's not possible to render images that way. Since your bundle must know exactly all images it should load before the app runs, all images paths should be static. I haven't check if any new release fixed it, but as far as I know, that's how it works
@Green, Yes, the code provided does answer the question, just pay attention to the code under // GOOD comment. As I mentioned in the answer text, It represents the correct way to assign an image variable. Also, the official docs are the best resources for answering questions. No shame on copying/pasting from it.
|
8

If you have indexes in the data then my approach to the issue is:

const image1 = require('../assets/images/image1.png');
const image2 = require('../assets/images/image2.png');
const image3 = require('../assets/images/image3.png');

const images = [image1, image2, image3];

...

<Image source={images[index]} />

2 Comments

I wanted a way which doesn't involve writing require('pathToImage') multiple times
This is genius!
3

Here's a helper component that I use quite often:

import your-image-name from '<path-to-image>';

const images = {
  your-image-name,
};

getImage = name => images[name];

export default getImage;

Then, inside the component you need the image:

import getImage from '<path>';

<Image source={getImage('your-image-name')} />

Importing the image within the helper function removes the need to use require().

From there, you can import all your images into the getImage component.

If you would like to take it a step further, you can create a new Image component that takes in name as a prop. For example:

import { Image as RNImage } from 'react-native';

import getImage from '<path>';

const Image = ({ name, source, ...props }) => (
  <RNImage
    source={name ? getImage(name) : source}
    {...props}
  />
);

export default Image;

Importing Image using as RNImage is used to avoid a duplicate declaration error.

Then

import Image from '<path>';

<Image name="your-image-name" />

This also leaves you the ability to use source as a prop within the new Image component in case you ever need to use a URI instead of a relative path. Along with any other props you need to pass.

From there, you will have access to the getImage component without having to import it across multiple components within your app.

Hope this helps!

Comments

2

//-Convert image path to Array list

   indexImag = [
    require("./img/KPN48-01.jpg"),
    require("./img/KPN48-02.jpg"),
    require("./img/KPN48-03.jpg")
  ];

//-data Feed--

dataFeed = [
    {
      id: 1,
      title: "Koisuru Fietune Cookie คุกกี้เสี่ยงทาย",
      subTitle: "128,136,082 views",
      imgId: 0
    },
    {
      id: 2,
      title: "BNK48 - คุกกี้เสี่ยงทาย Koisuru Fortune Cookie Cover",
      subTitle: "328,006,000 views",
      imgId: 1
    },
    {
      id: 3,
      title: "คลาสเด็ก - คุกกี้เสี่ยงทาย - BNK48 - Koisuru Fortune Cookie",
      subTitle: "334,111,234 views",
      imgId: 2
    },
    {
      id: 4,
      title:
        "เชิญชวนมาร่วมถ่าย MV BNK48 Koisuru Foutune Cookie คุกกี้เสี่ยงทาย",
      subTitle: "100,000,055 views",
      imgId: 0
    },
    {
      id: 5,
      title:
        "หนุ่มๆ ฟินทั้งประเทศ! ฟังเพลงฮิต คุกกี้เสี่ยงทาย อีก 3 เวอร์ชั่นจากวงพี่สาว ",
      subTitle: "400,143,634 views",
      imgId: 1
    }
  ];

//-render--

 <View>
    <View>
      <Image

        source={require("./img/LogoPP.png")}
      />
      <View>
        <Text>{_item.textTitle} </Text>
        <Text>{_item.subTitle} </Text>
      </View>
    </View>

    <Image

      source={this.indexImag[_item.imgId]}
    />
  </View>

1 Comment

Perfect Solution
0

The solution there if you have more than 2 choices is to pass the result of the require as a parameter instead of do a require(param) inside the method.

render() {
   return (
    <ScrollView>
        {this.renderMenuItem("CATALOGO", require('../../img/hp_catalogo.jpg'), this.goToCatalogo)}
        {this.renderMenuItem("NOVITÀ PRODOTTI", require('../../img/hp_novita.jpg'), this.goToNovita)}
    </ScrollView>);
}

renderMenuItem(name, imagePath, func ){
     return (
         <TouchableOpacity onPress={func} style={styles.box}>
         <ImageBackground
           source={imagePath}
           style={styles.image}>
           <Text>{name}</Text>
         </ImageBackground>
         <TouchableOpacity>);
         }

1 Comment

I've multiple choices & it gives me headache require(whole path to image) multiple times, I just posted to know if there is a better alternate than writing require() equal to number of choices.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.