Muhammad Saqib
Muhammad Saqib

Reputation: 1117

How do I invalidate the old images when request for a new one is initiated in React?

Have a look my code below, I have create a pen for it too: https://codepen.io/segmentationfaulter/pen/YEEaxK

The problem is that when I click on change image button, the old image stays there for a while until the new image is loaded. What I want is that the old image is invalidated straight away and empty space is shown for the new image. How can I achieve this in react? If you can't spot the issue, try opening it in private mode so that caching doesn't affect it.

const images = [
  'http://via.placeholder.com/550x550',
  'http://via.placeholder.com/750x750'
]

class MyImage extends React.Component {
  constructor() {
    super()
    this.state = {
      currentImageIndex: 0
    }
  }
  changeImage() {
    this.setState((prevState) => {
      if (prevState.currentImageIndex) {
        return {
          currentImageIndex: 0
        }
      } else {
        return {
          currentImageIndex: 1
        }
      }
    })
  }
  render() {
    return ( <
      div >
      <
      img src = {
        this.props.images[this.state.currentImageIndex]
      }
      /> <
      button onClick = {
        this.changeImage.bind(this)
      } >
      change image <
      /button> <
      /div>
    )
  }
}

ReactDOM.render( < MyImage images = {
      images
    }
    />, document.getElementById('root'))
img {
  display: block;
}

button {
  margin-top: 15px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root">
  <div>

Upvotes: 1

Views: 1008

Answers (3)

user8567417
user8567417

Reputation:

Possible way may be:

  1. put empty picture if state is changed

  2. fetch the image and then replace empty image from response

Upvotes: 0

Hemerson Carlin
Hemerson Carlin

Reputation: 7424

You could use, for example, onLoad prop from img where you toggle a loading in state so you can render the placeholder.

The strategy around it is:

  • display the placeholder and hide the image if loading is true
  • hide the loading when the image has been loaded.

PS: I added a timeout so you can see the placeholder in action.

const images = [
  'http://via.placeholder.com/550x550',
  'http://via.placeholder.com/750x750'
]

class Images extends React.Component {
  constructor() {
    super()

    this.state = {
      currentImageIndex: 0,
      loading: true,
    }
  }

  handleLoad() {
    setTimeout(() => {
      this.setState({ loading: false })
    }, 1000)
  }
  
  changeImage() {
    this.setState((prevState) => {
      if (prevState.currentImageIndex) {
        return {
          currentImageIndex: 0
        }
      }
      return {
        currentImageIndex: 1
      }
    })
  }

  render() {
    const { loading, currentImageIndex } = this.state
    
    return (
      <div>
        {loading && <div>placeholder comes here</div>}
        <img
          onLoad={this.handleLoad.bind(this)}
          src={images[currentImageIndex]}
          style={{ display: loading ? 'none' : 'block' }}
        />
        <button onClick={this.changeImage.bind(this)}>
          change image
        </button>
      </div>
    )
  }
}

ReactDOM.render(
  <Images />,
  document.getElementById('root')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="root"></div>

Upvotes: 1

Kriz Poon
Kriz Poon

Reputation: 169

Try to assign a random key prop to the img element every time it switches to another image. This forces react to recreate the element.

constructor () {
  super()
  this.state = {
    currentImageIndex: 0,
    imgKey: Math.random()
  }
}
changeImage () {
   this.setState((prevState) => {
     if (prevState.currentImageIndex) {
       return { currentImageIndex: 0, imgKey: Math.random() }
     } else {
       return { currentImageIndex: 1, imgKey: Math.random() }
     }
   })
 }

render () {
    return (
      <div>
        <img key={this.state.imgKey} src={this.props.images[this.state.currentImageIndex]} />
        <button onClick={this.changeImage.bind(this)}>
          change image
        </button>
      </div>
    ) 
  }
}

Upvotes: 3

Related Questions