I would like to reload an image at a static URL indefinitely in React. Through some searching I arrived at the below less than ideal solution. It works, but I would like to remove the flickering of the image loading. I realize the issues is that the ponent is re-rendered, and then the image loads. I've seen a couple examples that use the two images one as a placeholder and the loading one hidden until it loads using onLoad
and setState
, but they all assume a finite number of images. How can I make this display the last image in the CardMedia
until the new one is loaded and then replaced without flicker every five seconds?
import React from 'react';
import ReactDOM from 'react-dom';
import { Card, CardMedia, CardTitle } from 'react-toolbox/lib/card';
const LIVE_IMAGE = '*oi8WLwC2u0EEI1j9uKmwWg.png';
class LiveImageCard extends React.Component {
constructor(props) {
super(props);
this.state = {
liveImage: null
};
}
ponentDidMount() {
this.interval = setInterval(
() => this.setState({
liveImage: `${LIVE_IMAGE}?${new Date().getTime()}`,
}),
5000
);
}
ponentWillUnmount() {
clearInterval(this.interval);
}
render() {
return (
<Card style={{width: '350px'}}>
<CardTitle title="Live Image" />
<CardMedia
aspectRatio="wide"
image={this.state.liveImage}
/>
</Card>
);
}
}
ReactDOM.render(
<LiveImageCard />,
document.getElementById('root'),
);
I would like to reload an image at a static URL indefinitely in React. Through some searching I arrived at the below less than ideal solution. It works, but I would like to remove the flickering of the image loading. I realize the issues is that the ponent is re-rendered, and then the image loads. I've seen a couple examples that use the two images one as a placeholder and the loading one hidden until it loads using onLoad
and setState
, but they all assume a finite number of images. How can I make this display the last image in the CardMedia
until the new one is loaded and then replaced without flicker every five seconds?
import React from 'react';
import ReactDOM from 'react-dom';
import { Card, CardMedia, CardTitle } from 'react-toolbox/lib/card';
const LIVE_IMAGE = 'https://cdn-images-1.medium./max/1600/1*oi8WLwC2u0EEI1j9uKmwWg.png';
class LiveImageCard extends React.Component {
constructor(props) {
super(props);
this.state = {
liveImage: null
};
}
ponentDidMount() {
this.interval = setInterval(
() => this.setState({
liveImage: `${LIVE_IMAGE}?${new Date().getTime()}`,
}),
5000
);
}
ponentWillUnmount() {
clearInterval(this.interval);
}
render() {
return (
<Card style={{width: '350px'}}>
<CardTitle title="Live Image" />
<CardMedia
aspectRatio="wide"
image={this.state.liveImage}
/>
</Card>
);
}
}
ReactDOM.render(
<LiveImageCard />,
document.getElementById('root'),
);
Share
Improve this question
edited Apr 17, 2018 at 2:34
Rob Cannon
asked Apr 17, 2018 at 2:25
Rob CannonRob Cannon
3925 silver badges16 bronze badges
2
-
The issue es from the fact that you are switching the image source in your
CardMedia
when the image starts loading (but isn't fully loaded). Your Card Media ponent should handle that for you or you will have to write your own and use intermediate 1s timeout in between the time the image starts loading and you swap the HTML img source: stackoverflow./questions/5438612/… – klugjo Commented Apr 17, 2018 at 2:38 -
I appreciate the response, but your ment is glossing over the problem. I've tried a number of ways to do what you are suggesting, and none of them work. For instance, to do what you are suggesting, I could make my
setInterval
function something likeconst img = new Image(); img.onload = () => this.setState({ liveImage: img }); img.src = `${LIVE_IMAGE}?${new Date().getTime()}`; this.setState({ temp: img });
but React or the React-Toolbox doesn't like using theImage
object in theCardMedia
attribute. – Rob Cannon Commented Apr 17, 2018 at 12:55
2 Answers
Reset to default 3For me, removing <Image>
props, resizeMode={"contain"}
solved flickering issue on Android.
Not sure if this is the best solution, but I ended up with this and it works such that you don't see the flicker.
import React from 'react';
import ReactDOM from 'react-dom';
import { Card, CardMedia, CardTitle } from 'react-toolbox/lib/card';
const LIVE_IMAGE = 'https://cdn-images-1.medium./max/1600/1*oi8WLwC2u0EEI1j9uKmwWg.png';
class LiveImageCard extends React.Component {
constructor(props) {
super(props);
this.loadImage = () => {
const ponent = this;
const img = new Image();
img.crossOrigin = "Anonymous";
img.onload = function () {
var canvas = document.createElement("canvas");
canvas.width =this.width;
canvas.height =this.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0);
var dataURL = canvas.toDataURL("image/png");
ponent.setState({liveImage: dataURL});
};
img.src = `${LIVE_IMAGE}?${new Date().getTime()}`;
this.setState({ loadingImage: img });
}
this.state = {
loadingImage: null,
liveImage: null
};
}
ponentDidMount() {
this.loadImage();
this.interval = setInterval(this.loadImage, 5000);
}
ponentWillUnmount() {
clearInterval(this.interval);
}
render() {
return (
<Card style={{width: '350px'}}>
<CardTitle title="Live Image" />
<CardMedia
aspectRatio="wide"
image={this.state.liveImage}
/>
</Card>
);
}
}
ReactDOM.render(
<LiveImageCard />,
document.getElementById('root'),
);
Or as a standalone ponent without the React-Toolbox
class LiveImage extends React.Component {
constructor(props) {
super(props);
this.loadImage = () => {
const ponent = this;
const img = new Image();
img.crossOrigin = "Anonymous";
img.onload = function () {
var canvas = document.createElement("canvas");
canvas.width =this.width;
canvas.height =this.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0);
var dataURL = canvas.toDataURL("image/png");
ponent.setState({liveImage: dataURL});
};
img.src = `${this.props.image}?${new Date().getTime()}`;
this.setState({ loadingImage: img });
}
this.state = {
loadingImage: null,
liveImage: null
};
}
ponentDidMount() {
this.loadImage();
this.interval = setInterval(this.loadImage, this.props.interval);
}
ponentWillUnmount() {
clearInterval(this.interval);
}
render() {
return (
<img src={this.state.liveImage} {...this.props} />
);
}
}