In isomorphic rendered page image can be downloaded before main script.js
file. So image can be already loaded before react
register onLoad
event - never trigger this event.
script.js
constructor(props) {
super(props);
this.handleImageLoaded = this.handleImageLoaded.bind(this);
}
handleImageLoaded() {
console.log('image loaded');
}
render() {
return (
<img src='image.jpg' onLoad={this.handleImageLoaded} />
);
}
image.jpg
is bigger than script.js
In this scenario everything is working fine. Event is registered before image is finally loaded so in console is image loaded
message.
image.jpg
is smaller than script.js
This scenario you can see problem described at the beginning of post. onLoad
event is not triggered.
What can I do in order to trigger onLoad
event in scenario 2?
To detect if image is ready on render you should check complete
property on pure javascript img
object:
constructor(props) {
super(props);
this.state = { loaded: false };
this.handleImageLoaded = this.handleImageLoaded.bind(this);
this.image = React.createRef();
}
componentDidMount() {
const img = this.image.current;
if (img && img.complete) {
this.handleImageLoaded();
}
}
handleImageLoaded() {
if (!this.state.loaded) {
console.log('image loaded');
this.setState({ loaded: true });
}
}
render() {
return (
<img src='image.jpg' ref={this.image} onLoad={this.handleImageLoaded} />
);
}
You could check the complete
property on the image before applying the onload
event.
if (!img.complete) {
// add onload listener here
}
This is all a bit tidier with Hooks:
const useImageLoaded = () => {
const [loaded, setLoaded] = useState(false)
const ref = useRef()
const onLoad = () => {
setLoaded(true)
}
useEffect(() => {
if (ref.current && ref.current.complete) {
onLoad()
}
})
return [ref, loaded, onLoad]
}
const SomeComponent = ({ src }) => {
const [ref, loaded, onLoad] = useImageLoaded()
return (
<div>
<img ref={ref} onLoad={onLoad} src={src} alt="" />
{loaded && <h1>Loaded!</h1>}
</div>
)
}
Another way is to use ref and cover those both scenarios:
<img
ref={(input) => {
// onLoad replacement for SSR
if (!input) { return; }
const img = input;
const updateFunc = () => {
this.setState({ loaded: true });
};
img.onload = updateFunc;
if (img.complete) {
updateFunc();
}
}}
src={imgSrc}
alt={imgAlt}
/>
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