My goal is to have my gallery images render in as they load.
Looking online, I have learned about the onLoad
method.
This is what I have tried to utilise, the idea being that the preloader.gif
would render until the image is loaded and simply replace the image src with the loaded image.
As it is now(below), the images seem to load in the same way they normally would if I didn't use the onLoad
method so there is a moment where no image is being rendered at all before the images load in.
What am I doing wrong exactly?
I've stripped down the code to make the question easier to read.
import React from 'react';
import ReactDOM from 'react-dom';
import preloaderImage from '../../../img/site/preloader.gif';
class WorksPage extends React.Component {
constructor(){
super();
}
imageLoadHandler(image,e) {
e.target.src = image;
}
render() {
const listWork = this.props.array.map((item,index)=> {
return(
<li key={item.id}>
<div>
<img src={preloaderImage} onLoad={this.imageLoadHandler.bind(this,item.image)}/>
</div>
</li>
)
});
return(
<li>
<div>
<ul>
{listWork}
</ul>
</div>
</li>
)
}
}
module.exports = WorksPage;
preloader
image isn't rendered:preloaderImage
loadsimageLoadHandler
triggers and src
attribute is changed to the main image
src (so preloaderImage
isn't rendered even it is now loaded)If you write React app, you should do it React way:
Set your images to the component state
in its constructor
method. You need to do it because you are gonna change the way your images are rendered (in React you achieve render changes via changing either component's props
or state
, in your case it should be state
). But notice that you should set src
property for each image in the list to your preloaderImage
(in example below I am using object destructuring
syntax).
constructor() {
super();
this.state = {
images: this.props.images.map(image => ({
...image,
src: preloaderImage
}))
}
}
Now in render
method create the image list like this (note, you don't need onLoad
handler here):
const listWork = this.state.images.map(image => (
<li key={image.id}>
<div>
<img src={image.src} />
</div>
</li>
));
In componentWillMount
method start to load your primary images src
dynamically using vanilla JS (you can read article about it here
). As they are loaded call setState
method to update images src
property:
componentWillMount() {
this.state.images.forEach((image, index) => {
const {src} = this.props.images[index] // get image primary src
const primaryImage = new Image() // create an image object programmatically
primaryImage.onload = () => { // use arrow function here
console.log(`image #${index + 1} is loaded!`)
const images = [...this.state.images] // copy images array from state
images[index].src = src // adjust loaded image src
this.setState({
images
})
}
primaryImage.src = src // do it after you set onload handler
})
}
After setState
is called with changed images
array React will automatically rerender your images with correct src
path.
Instead of <img />
tag you can use <div />
tag with background-image
css property. There you can simply set your fallback (preload) image:
background-image: url('path/to/primary-image'), url('path/to/preload-image');
You can set paths dynamically with style
property (in your render
method):
const listWork = this.props.images.map(image => {
const imageStyle = {
backgroundImage: `url(${image.src}), url(${preloaderImage});`
}
return (
<li key={image.id}>
<div>
<div style={imageStyle} />
</div>
</li>
)
})
Just don't forget to set height
and width
to this <div />
.
Don't know if this helps but you could set a CSS property for your image while it is loading (e.g. opacity or visibility set not to display the image) and then change that CSS property when the onLoad
event is fired. You could use the same for your preloader image, but obviously in reverse mode.
You also should be able to set a fallback action if the image won't load, by calling the onError
function, also in the image that you are loading.
Hope this helps!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With