8
votes

I think this is a very annoying bug and feels like there is no solution but I want to share and ask.. I fetch data from server and I get image source from there and I use same Image paths in my mobile react-native App.

I fetch data from server like this :

$id = $request->userid;
$items = DB::table('item_user')->where('user_id', $id)->latest()->get();

$new = new Collection();

foreach($items as $item){

$new[] = array(
   ... ,
   'picturePath' => 'require'."('./". $item->picturePath ."')"
);

}

return $new;

and in front-end I try to render and I have these images locally. So when I use it locally like :

require('./images/...')

It works.. but like this its not working :

_renderItem = ({item}) => {

        return(
            <View>
               <Image source={ item.picturePath } style={{width: 15, height: 15}}/>
            </View>
        );

    };


    render(){
        return(

        <View>
           <FlatList
                data={this.state.items}
                renderItem={this._renderItem}
                keyExtractor={this._keyExtractor}
            />
         </View>
        );
    }

and I get error, How I can solve this :

Warning: Failed prop type: Invalid prop 'source' supplied to 'Image'.

2
react-native can't require static assets at runtime. It has to be at build time. - Adam
is your item.picturePath has full path including the http? - slashsharp
no it has like require('./images/.../..') and I have these images locally. So when I use it locally like require('./images/...'), it works.. - Berke

2 Answers

23
votes

This is not the recommended way to assign dynamically images since React Native must know all your images sources before compiling your bundle.

According to the docs, here's an example of how to load images dynamically:

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

Edit: If you know all the images that could be loaded, you can try something like this:

// Create a file containing the references for your images

// images.js
const images = {
  logo: {
    uri: require('your-image-path/logo.png')
  },
  banner: { 
    uri: require('your-image-path/banner.png')
  }
}

export { images }; 


//YourComponent.js
import { images } from 'yourImagesPath';

// for this test, expected to return [ { name: logo }, { name: banner} ]
const imagesFromTheServer = (your fetch);

imagesFromTheServer.map(image => {
  if (!images[image]) {
    return <Text>Image not found</Text>;
  }
  return <Image source={images[image].uri} />; // if image = logo, it will return images[logo] containing the require path as `uri` key
});

This is quite hacky but may work.

Let me know if it helped

13
votes

As the React Native Documentation says, all your images sources needs to be loaded before compiling your bundle.

Adding a simple image in React Native should be like this:

<Image source={require('./path_to_your_image.png')} />

Let's say you have this:

const slides = {
  car: './car.png',
  phone: '../phone.png',
}

Then you pass slides as a parameter but still, you won't be able to use it like this (even though logically should work):

<Image source={require(props.car)} />

Use require() inside the sildes{}

const slides = {
  car: require('./car.png'),
  phone: require('../phone.png'),
}

And the use it like this:

<Image source={props.car} />