AG_HIHI
AG_HIHI

Reputation: 2015

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

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?

Upvotes: 3

Views: 2272

Answers (3)

chococroqueta
chococroqueta

Reputation: 773

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'
/>

Upvotes: 1

b3hr4d
b3hr4d

Reputation: 4588

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>
       )
  }
}

Upvotes: 0

Werries
Werries

Reputation: 1

I think you are not declare to React what your state variables are. Normally you need to define the state as described in the docs of React https://reactjs.org/docs/state-and-lifecycle.html#adding-local-state-to-a-class

You would need to do something like this:

constructor(props) {
  super(props);
  this.state = {profileImageSrc: //the initial url you want}
}

Upvotes: 0

Related Questions