ReactJs: Refresh img tag after image update where url remains constant but the image from that url changes

Viewed 740

In my app, when user changes image, the url of the image remains the same, but the image in the cloud changes.
In other words, suppose the url of the image is URL1, after the user uploads his image, the image retrieved from that url changes, but the URL remains the same.

The problem with this is that React does not detect the change, and so does not refresh the image tag automatically, and I have to refresh the page, in order to see the new image.

Here's my code:

class ProfilePage extends Component {
  saveImageUrlInDatabase(profileImageURL) {
    const imageData = {
      profileImageURL: profileImageURL,
    };
    this.props.uploadProfilePictureURL(imageData);
  }

  async updateAvatar(event) {
    const imageFile = event.target.files[0];
    if (!imageFile) {
      return;
    }
    const imageURL = await this.props.uploadProfileImage(imageFile);
    this.saveImageUrlInDatabase(imageURL);
    this.setState({
      profileImageURL: imageURL,
    });
  }

  render() {
    const { profile, loading } = this.props.profile;

    if (!profile || loading) {
      profileContent = <Spinner />;
    } else {
      // #BUG: Even though profileImageSrc changes
      // It doesn't get update automatically

      // It turns out the url does not change
      // But, the image does change
      let profileImageSrc;
      // True if user has updated his image
      if (this.state.profileImageURL !== "") {
        profileImageSrc = this.state.profileImageURL;
      } else {
        profileImageSrc = !profile.profileImageURL
          ? require("assets/img/faces/lofi-girl.png")
          : profile.profileImageURL;
      }

      profileContent = (
        <Container>
          <div className="owner">
            <div className="avatar">
              <Label for="avatar-upload">
                <img
                  alt="..."
                  className="img-circle img-no-padding img-responsive"
                  src={profileImageSrc}
                  key={Math.floor(Math.random() * 10)}
                  style={{
                    cursor: "pointer",
                  }}
                  title="Change profile image"
                />
              </Label>

              <input
                id="avatar-upload"
                type="file"
                accept="image/*"
                style={{ display: "none" }}
                onChange={this.updateAvatar}
              />
            </div>
          </div>
        </Container>
      );
    }
    return <div className="section profile-content">{profileContent}</div>;
  }
}

Any idea how to solve this?

3 Answers

Your component has some issue, try this:

import fallbackImage from "./assets/img/faces/lofi-girl.png";

class ProfilePage extends Component {
  constructor(props) {
    super(props)
    this.state = {
      profileImageURL: props.profile.profileImageURL,
    }
  }

  saveImageUrlInDatabase(profileImageURL) {
    const imageData = {
      profileImageURL: profileImageURL,
    };
    this.props.uploadProfilePictureURL(imageData);
  }

  async updateAvatar(event) {
    const imageFile = event.target.files[0];
    if (!imageFile) {
      return;
    }
    const imageURL = await this.props.uploadProfileImage(imageFile);
    this.saveImageUrlInDatabase(imageURL);
    this.setState({
      profileImageURL: imageURL,
    });
  }

  render() {
    const { profile, loading } = this.props.profile;
    const { profileImageURL } = this.state;
    return (
      <div className="section profile-content">
        {!profile || loading && <Spinner />}
        <Container>
              <div className="owner">
                <div className="avatar">
                  <Label for="avatar-upload">
                    <img
                      alt="..."
                      className="img-circle img-no-padding img-responsive"
                      src={
                        profileImageURL ? 
                        profileImageURL : 
                        fallbackImage
                      }
                      key={Math.floor(Math.random() * 10)}
                      style={{
                        cursor: "pointer",
                      }}
                      title="Change profile image"
                    />
                  </Label>

                  <input
                    id="avatar-upload"
                    type="file"
                    accept="image/*"
                    style={{ display: "none" }}
                    onChange={this.updateAvatar}
                  />
                </div>
              </div>
            </Container>
          </div>
       )
  }
}

I was facing the same problem: I was updating the image in a url but the url was the same. The image didn't update because the brower saved the image in caché. What I'm doing is to add a random number to the end of the url. If the component is different, it will update alone; otherwise, you can add a button to update the random number. Something like:

const [random, setRandom] = React.useState(1)

render

<button onClick={()=>setRandom(Math.random())}>
    update image
<button/>
<img
    className = 'img-miniatura'
    src = {url+'?n='+random}
    alt='miniatura'
/>
Related