Is there a way to check if an image exists before setting the image source in React when the image source has concatenated variables?

Viewed 17644

I'm creating a component that contains an image with a dynamic source. It's dynamic in that it takes 3 props that get concatenated into the URL of the image. No matter what I try, I can't seem to get it to stop giving me the error, 'Cannot find module' for images that don't exist.

I have tried checking to see if the image exists with the image-exists package and using ajax to check if the image exists. I have also tried adding onError to change the state from the URL.

import React from "react";

export class Drawing extends React.Component {
    constructor(props) {
        super(props);
        this.state = { src: "" };
        this.setSource = this.setSource.bind(this);
    }

    setSource() {
        this.setState({
            src: require(`../../../../img/products/${this.props.type}/models/${this.props.product}-${this.props.model.replace(/\s+/g, "-").toLowerCase()}-specs-drawing.png`)
        });
    }

    componentWillMount() {
        this.setSource();
    }

    render() {
        return <img src={this.state.src} alt="Specification Drawing" />;
    }
}

It almost seems as the the componentWillMount is getting called every time I change the dropdown selection. The dropdown changes the model which will change the image source based on the dropdown. It is showing the image correctly only if the image for that path exists. Otherwise it gives me the error, 'Cannot find module ...image-path'.

4 Answers

You can use a simple try/catch block :

setSource() {
    try{
        const src = require(`../../../../img/products/${this.props.type}/models/${this.props.product}-${this.props.model.replace(/\s+/g, "-").toLowerCase()}-specs-drawing.png`)
        this.setState({ src });
    }
    catch(err){
        //Do whatever you want when the image failed to load here
    }
}

Using this you can define the behavior of your application if the image loading failed into the catch block without having your program crashing

Use the Javascript promise function to check whether image is exist or not.

try something like this.

const checkImage = path =>
 new Promise(resolve => {
    const img = new Image();
    img.onload = () => resolve({path, status: 'ok'});
    img.onerror = () => resolve({path, status: 'error'});

    img.src = path;
});

You should never use async operations in componentWillMount or constructor. Instead do it in componentDidMount.

componentDidMount() {
    this.setSource();
}

i did the following thing and it works smoothly

1.first you need a function which returns t/f for checking if your img url exists like this :

(i used axios , you can use simple promise)

export function CheckImage(path) {
  axios
    .get(path)
    .then(() => {
      return true;
    })
    .catch(() => {
      return false;
    });
}

2.then in your img tag ,src attribute do this :

(path is the path to your image or url/ mainImage is your sample image path didnt exists)

      <img
        src={CheckImage(path) ? path : mainImage}
        alt={...}
      />
Related