I'm currently rendering a child ponent when a signInError
occurs. The signInError
is stored in the parent ponent and if it's not null, it renders the <SignInError/>
ponent, as per the code below:
ParentComponent.js
// Some code...
render() {
return(
<div>
<SignInForm
doSignIn={this.doSignIn}
resetSignInError={this.resetSignInError}
signInError={this.state.signInError}
/>
{this.state.signInError && <SignInError/>}
</div>
);
}
So far, so good, here's the child ponent SignInError.js
import React from 'react';
import RoundImage from '../../../UI/Common/RoundImage';
import Newman from '../../../../assets/newman-min.png';
class SignInError extends React.Component {
constructor(props){
super(props);
}
ponentDidMount(){
const img = new Image();
img.src = Newman;
}
render(){
return(
<div>
<div>
<RoundImage src={img.src}/> // <--- img is undefined here!!!
</div>
<div>
Hello... Newman!
</div>
</div>
);
}
}
export default SignInError;
RoundImage.js
import React from 'react';
const RoundImage = (props) => {
return (
<div>
<img src={props.src}/>
</div>
);
}
export default RoundImage;
How to preload images in React.js?
This question's answer (link above) here on Stack Over flow tells me to create the img
object inside the ponentDidMount()
method to force the browser to load it. And so I did, as you can see from the code above. But now, when I try to pass it as a prop to my grand-child ponent inside my render
method, I can't access the img
, because it was defined inside of another method.
What's the best way around this? I just need the image to be loaded and to be displayed together with the error message. Otherwise the error message will show before the image, if your browser hasn't cached it yet. Thanks for the help.
I'm currently rendering a child ponent when a signInError
occurs. The signInError
is stored in the parent ponent and if it's not null, it renders the <SignInError/>
ponent, as per the code below:
ParentComponent.js
// Some code...
render() {
return(
<div>
<SignInForm
doSignIn={this.doSignIn}
resetSignInError={this.resetSignInError}
signInError={this.state.signInError}
/>
{this.state.signInError && <SignInError/>}
</div>
);
}
So far, so good, here's the child ponent SignInError.js
import React from 'react';
import RoundImage from '../../../UI/Common/RoundImage';
import Newman from '../../../../assets/newman-min.png';
class SignInError extends React.Component {
constructor(props){
super(props);
}
ponentDidMount(){
const img = new Image();
img.src = Newman;
}
render(){
return(
<div>
<div>
<RoundImage src={img.src}/> // <--- img is undefined here!!!
</div>
<div>
Hello... Newman!
</div>
</div>
);
}
}
export default SignInError;
RoundImage.js
import React from 'react';
const RoundImage = (props) => {
return (
<div>
<img src={props.src}/>
</div>
);
}
export default RoundImage;
How to preload images in React.js?
This question's answer (link above) here on Stack Over flow tells me to create the img
object inside the ponentDidMount()
method to force the browser to load it. And so I did, as you can see from the code above. But now, when I try to pass it as a prop to my grand-child ponent inside my render
method, I can't access the img
, because it was defined inside of another method.
What's the best way around this? I just need the image to be loaded and to be displayed together with the error message. Otherwise the error message will show before the image, if your browser hasn't cached it yet. Thanks for the help.
Share Improve this question edited Jan 8, 2019 at 16:41 cbdeveloper asked Jan 8, 2019 at 16:34 cbdevelopercbdeveloper 31.5k45 gold badges201 silver badges396 bronze badges 5- What is "RoundImage"? – Diodeus - James MacFarlane Commented Jan 8, 2019 at 16:37
-
If RoundImage is expecting a path, why not just use:
<RoundImage src={Newman}/>
? – Diodeus - James MacFarlane Commented Jan 8, 2019 at 16:41 - I've just edited to add the RoundImage.js code. Thanks. – cbdeveloper Commented Jan 8, 2019 at 16:41
- @Diodeus-JamesMacFarlane I tried that. It works, but it doesn't preload my image. "Hello Newman!" shows before the image. And then, once the browser downloads it, it loads... – cbdeveloper Commented Jan 8, 2019 at 16:43
- If you want to pre-load it, you need to create the new Image() higher up in your app. By the time the ponent loads it still doesn't have the image. You don't need to reference this image, you just want to force the browser to fetch it. When you use it in your ponent, it will already be cached. – Diodeus - James MacFarlane Commented Jan 8, 2019 at 16:47
3 Answers
Reset to default 28Image download happens in the browser. Rendering to the DOM also happens in the browser.
By preloading, do you mean that you want that the ponent renders only when the image is ready?
If so, you could do something like this:
ponentDidMount() {
const img = new Image();
img.onload = () => {
// when it finishes loading, update the ponent state
this.setState({ imageIsReady: true });
}
img.src = Newman; // by setting an src, you trigger browser download
}
render() {
const { imageIsReady } = this.state;
if (!imageIsReady) {
return <div>Loading image...</div>; // or just return null if you want nothing to be rendered.
} else {
return <img src={Newman} /> // along with your error message here
}
}
A bit of a different approach, but if you have the image source in advance, you can add the image source to the main html file as a link ref with preload option. The browser will preload the image (with relatively low priority) and at the time your app will load the image, it should be cached in the browser memory.
<head>
..
..
<link rel="preload" href="<your_image_source_here>" as="image">
...
</head>
In this approach, we separate the preloading process from the code. It is more relevant when you have the image source in advance (and not dynamically) and when you don't need to cache a large amount of images (will be a bit messy to add a large list of links in the html head, although possible)
you can learn more about link preloading here: Preloading content with rel="preload"
In my case I start with an initial src attribute for my images and wanted to delay changing them after the image has been loaded by the browser, so I wrote the following hook in Typescript:
import { useEffect, useState } from 'react';
export const useImageLoader = (initialSrc: string, currentSrc: string) => {
const [imageSrc, _setImageSrc] = useState(initialSrc);
useEffect(() => {
const img = new Image();
img.onload = () => {
_setImageSrc(currentSrc);
};
img.src = currentSrc;
}, [currentSrc]);
return [imageSrc];
};