23

I have a js file with one component EventCard, which takes event name, date, event image etc. If event image does not exist I want to load a placeholder image. Now that statement looks like this

constructor(props){
    super(props);
    let imgUrl = props.image ? props.image : require("../assets/images/image.jpg");
    this.state = {image: imgUrl}
}

I am using this.state inside render for source like

source={{uri: this.state.image}}

I strangely get 11 when doing a require for the placeholder image and the react native throws error saying 'value for uri cannot be cast from Double to String'.

Help is much appreciated.

Thanks

Kireeti K
  • 1,370
  • 1
  • 19
  • 32

8 Answers8

21

You need to assign image source directly when using require.

constructor(props){
  super(props);
  let imgUrl = props.image ? { uri: props.image } : require("../assets/images/image.jpg");
  this.state = { image: imgUrl };
}

and then in your render:

source={this.state.image}
Fawaz
  • 3,404
  • 3
  • 17
  • 22
  • 1
    Thanks for the effort, It does work. What I previously didn't know is that require returns a number and your answer makes me think of this. – Kireeti K Sep 19 '18 at 06:35
  • 1
    Glad it helped @KireetiK. I had experienced the same before! – Fawaz Sep 19 '18 at 06:36
  • Damn! How did I missed that, it's like that in the official documents, but they didn't put any warning to be aware of the difference. Thank you! – KeitelDOG May 23 '22 at 01:55
11

After some research and some help from @Fawaz and @Haider I understood require returns a number. This means we can use a number directly with source instead of require and it works

<Image source={11} />

This should display an image from your local resource if you have any image corresponding to that number. So when wanting to decide whether to show server sent url or a local resource like in my case. we can go with @Fawaz answer which basically inserts a {uri: "image-link"} or require("image") where require will be resolved to a number and when used with source you will put either the object or number which are the standard ways according to the documentation.

Kireeti K
  • 1,370
  • 1
  • 19
  • 32
  • I don't believe this to be true. I have the exact same scenario and I receive the error: *JSON value '49' of type NSNumber cannot be converted to a valid URL.* – Stephen Tetreault Oct 15 '18 at 21:02
  • Do you have any image that corresponds to that value? Please note I am no expert at this matter, I am only sharing my observations. – Kireeti K Oct 16 '18 at 08:23
  • 1
    This was a silly mistake on my end! After fixing some code, removing the URI part since its a local image, it was running without errors. However no image rendering, I wasn't paying attention and was trying to load in SVGs as the image source. Swapping them out for PNGs fixed it of course! – Stephen Tetreault Oct 16 '18 at 16:15
  • 1
    I was feeling a headache because of this issue. Finally, I found your answer that was very helped me. You are the best thanks. – Halil İbrahim Özdoğan Jan 07 '20 at 10:19
  • This is true. In `@types/react-native`, the `ImageSourcePropType` can be a number and `ImageRequireSource` type is just an alias of `number` type. – MJ Studio Sep 14 '20 at 05:29
  • Definitely not a good idea to pass number literals to the source prop as they can change if you add more requires to your code. – ICW Jun 15 '21 at 19:19
  • 2
    Can someone explain how the literal value is mapped to the local resource? If possible do share some URL related to it! – Mohit Patil Dec 09 '21 at 09:17
  • Didn't know that too. The same thing as StyleSheet, they reference it to a number, like a Database, and they will replace it with its true value when done. – KeitelDOG May 23 '22 at 01:58
1

You can simply do this

constructor(props){
    super(props);
    let imgUrl = props.image ? props.image : null
    this.state = {image: imgUrl}
}

source={imgUrl == null ? require("../assets/images/image.jpg") : this.state.image}
Haider Ali
  • 1,275
  • 7
  • 20
0

Do not use the require dynamically. Detailed explanation in this post: React Native - Image Require Module using Dynamic Names

gazdagergo
  • 6,187
  • 1
  • 31
  • 45
0
You can try this,

import React, {Component} from 'react';
import {StyleSheet,ImageBackground} from 'react-native';

import bgSrc from './images/bgfrm.png';

export default class Wallpaper extends Component {
  constructor(props){
    super(props);
    let imgUrl = props.image ? props.image :bgSrc;
    this.state = {image: imgUrl};
}

  render() {
    return (
      <ImageBackground style={styles.picture} source={this.state.image}>
        {this.props.children}
      </ImageBackground>
    );
  }
}

const styles = StyleSheet.create({
  picture: {
    flex: 1,
    width: null,
    height: null,
    resizeMode: 'cover',
  },
});
Uthaya
  • 1
  • 3
0

Internally, React Native static image require resolved as a number.

I can prove with the React Native typescript type declaration.

// your file
import { ImageSourcePropType } from 'react-native';

// @types/react-native
/**
 * @see https://facebook.github.io/react-native/docs/image.html#source
 */
export type ImageSourcePropType = ImageURISource | ImageURISource[] | ImageRequireSource;
...
export type ImageRequireSource = number;


The ImageRequireSource type is just a number type. And it can be a one of ImageSourcePropType.

MJ Studio
  • 3,947
  • 1
  • 26
  • 37
0

If you went down the rabbit hole of discovering this because nothing is showing, remember to set the height and width of the image too in order for it to display. Once set, the require and import methods were working for me.

Asher
  • 393
  • 3
  • 16
-1

According to the documentation, the source prop of <Image /> only takes in a path to the resource (either local or remote). Here's how that might look in your example:

import React, { Component } from 'react';
import { Image } from 'react-native';


class EventCard extends Component {

  constructor(props) {
    super(props);

    const imgUrl = props.image || require('../assets/images/image.jpg');
    this.state = { image: imgUrl };
  }

  render() {
    return (
      <Image
        source={this.state.image}
      />
    );
  }
}

export default EventCard;
leitdeux
  • 94
  • 1
  • 6
  • Hey leitdeux, What you are suggesting is close to what I tried and it clearly doesnt work. Thanks for the effort though. – Kireeti K Sep 19 '18 at 06:31
  • You're right. I did misunderstand the problem and also didn't realize that the object, (i.e. `{ uri: '' }`) could be passed into the `source` prop. – leitdeux Sep 19 '18 at 06:44
  • I am glad my question generated some interest and could help me and someone else as well. – Kireeti K Sep 19 '18 at 06:47