20

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,134
  • 1
  • 16
  • 29

7 Answers7

20

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,049
  • 2
  • 15
  • 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,134
  • 1
  • 16
  • 29
  • 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,205
  • 6
  • 20
0

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

gazdagergo
  • 5,057
  • 1
  • 27
  • 40
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
  • 2,835
  • 17
  • 32
-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
  • 86
  • 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