How to loop over images in my app

I m trying to set images. It works fine when I set the first image, but when I try to upload a second image, it creates a second image box, but does not display anything on it, instead displays it on top of the first image box. I want them to be separate from each other.

I have tried to use blob directly by returning imgUrl (return imgUrl) in showImage function, but it also does not set blob in img src. How can I loop over and set all images separately in each box as soon as pic (URL) is received?

class Card extends Component {
  constructor({props, pic, token}) {
    super(props, pic, token);
    this.state = { 
      pic: pic
    };

readResponseAsBlob(response) {
  return response.blob();
}

validateResponse(response) {
  if (!response.ok) {
    throw Error(response.statusText);
  }
  return response;
}

logError(error) {
  console.log('Looks like there was a problem: \n', error);
}

showImage(responseAsBlob) {
  var container = document.getElementById('images');
  var imgElem = container.getElementsByTagName('img')[0];
  var imgUrl = URL.createObjectURL(responseAsBlob);
  imgElem.src = imgUrl;
  console.log(imgUrl);
}


  urlFetch(data) {
   fetch(data, { 
   headers: new Headers({
     'authorization': `Bearer ${this.props.token}`, 
     'Content-Type': 'application/json'
    })
  })
    .then(this.validateResponse)
    .then(this.readResponseAsBlob)
    .then(this.showImage)
    .catch(this.logError);
  }


  render() {
    const { pic } = this.state;

return (
             <a style={{width: 200, height: 250}} className='tc dib br3 ma2 pa2 grow bw2 shadow-5'>
              <div id='images'>
               <img style={{width: 175, height: 175}} className='tc myimage br3' alt='none' src={ this.urlFetch(pic) }/>
              </div>
              </a>
   );
  }
}

1 answer

  • answered 2018-05-16 05:59 Umair Abid

    The problem might be here src={ this.urlFetch(pic) } The function urlFetch is returning a promise instead of actual image path or data. Call this function in componentDidMount hook and the set the image you receive from backend in state and use that state property as src of image.

    I can see that urlFetch function manually modifying the DOM to set the image src, this is sort of confusing since the function you are calling is doing its job implicitly and modifying DOM in react is not a good practice at all and var imgElem = container.getElementsByTagName('img')[0]; will only modify the first image since you are getting the first img in the container

    I would also suggest to render each image in their respective component declare a state property which will hold the src of image, fetch the image of server and then update the state.

    class Card extends Component {
    
      constructor({props, token}) {
        super(props, token);
        this.state = { 
          src: ''
        };
      }
    
     readResponseAsBlob = (response) => {
      return response.blob();
     }
    
    showImage = (responseAsBlob) => {
    this.setState({ src: URL.createObjectURL(responseAsBlob) });
     }
    
      componentDidMount() {
        this.urlFetch(this.props.pic)
      }
    
      logError(error) {
        console.log('Looks like there was a problem: \n', error);
      }
    
      urlFetch(data) {
        fetch(data, { 
        headers: new Headers({
           'authorization': `Bearer ${this.props.token}`, 
           'Content-Type': 'application/json'
          })
        })
        .then(this.validateResponse)
        .then(this.readResponseAsBlob)
        .then(this.showImage)
        .catch(this.logError);
      }
    
    
      render() {
        const { src } = this.state;
    
        return (
          <a style={{width: 200, height: 250}} className='tc dib br3 ma2 pa2 grow bw2 shadow-5'>
            <div id='images'>
              <img style={{width: 175, height: 175: display: src ? 'block': 'none'}} className='tc myimage br3' alt='none' src={ src }/>
            </div>
          </a>
        );
      }
    }