最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Reload Live Image without Flickering in React - Stack Overflow

programmeradmin4浏览0评论

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 like const 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 the Image object in the CardMedia attribute. – Rob Cannon Commented Apr 17, 2018 at 12:55
Add a ment  | 

2 Answers 2

Reset to default 3

For 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} />
    );
  }
}
发布评论

评论列表(0)

  1. 暂无评论