Перезагрузите живое изображение без мерцания в React

Я хотел бы бесконечно перезагружать изображение по статическому URL-адресу в React. Через некоторые поиски я пришел к нижеприведенному менее чем идеальному решению. Работает, но хотелось бы убрать мерцание загрузки изображения. Я понимаю, что проблема в том, что компонент повторно отображается, а затем загружается изображение. Я видел пару примеров, в которых два изображения используются в качестве заполнителя, а загружаемое скрыто до тех пор, пока оно не загрузится с использованием onLoad и setState, но все они предполагают конечное количество изображений. Как я могу сделать так, чтобы это отображалось последним изображением в CardMedia, пока новое не загрузится, а затем заменится без мерцания каждые пять секунд?

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.com/max/1600/1*oi8WLwC2u0EEI1j9uKmwWg.png';

class LiveImageCard extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      liveImage: null
    };
  }

  componentDidMount() {
    this.interval = setInterval(
      () => this.setState({
        liveImage: `${LIVE_IMAGE}?${new Date().getTime()}`,
      }),
      5000
    );
  }
  componentWillUnmount() {
    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'),
);

person Rob Cannon    schedule 17.04.2018    source источник
comment
Проблема возникает из-за того, что вы переключаете источник изображения в своем CardMedia, когда изображение начинает загружаться (но загружается не полностью). Ваш компонент Card Media должен справиться с этим за вас, иначе вам придется написать свой собственный и использовать промежуточный тайм-аут 1 с между временем загрузки изображения и заменой источника изображения HTML: stackoverflow.com/questions/5438612/   -  person klugjo    schedule 17.04.2018
comment
Я ценю ответ, но ваш комментарий замалчивает проблему. Я пробовал несколько способов сделать то, что вы предлагаете, и ни один из них не работает. Например, чтобы сделать то, что вы предлагаете, я мог бы сделать свою функцию setInterval чем-то вроде const img = new Image(); img.onload = () => this.setState({ liveImage: img }); img.src = `${LIVE_IMAGE}?${new Date().getTime()}`; this.setState({ temp: img });, но React или React-Toolbox не любят использовать объект Image в атрибуте CardMedia.   -  person Rob Cannon    schedule 17.04.2018


Ответы (2)


Для меня удаление <Image> реквизита resizeMode={"contain"} решило проблему мерцания на Android.

person Nay    schedule 03.04.2019

Не уверен, что это лучшее решение, но я остановился на этом, и он работает так, что вы не видите мерцания.

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.com/max/1600/1*oi8WLwC2u0EEI1j9uKmwWg.png';

class LiveImageCard extends React.Component {
  constructor(props) {
    super(props);

    this.loadImage = () => {
      const component = 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");
        component.setState({liveImage: dataURL});
      };

      img.src = `${LIVE_IMAGE}?${new Date().getTime()}`;
      this.setState({ loadingImage: img });
    }

    this.state = {
      loadingImage: null,
      liveImage: null
    };
  }


  componentDidMount() {
    this.loadImage();
    this.interval = setInterval(this.loadImage, 5000);
  }
  componentWillUnmount() {
    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'),
);

Или как отдельный компонент без React-Toolbox

class LiveImage extends React.Component {
  constructor(props) {
    super(props);

    this.loadImage = () => {
      const component = 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");
        component.setState({liveImage: dataURL});
      };

      img.src = `${this.props.image}?${new Date().getTime()}`;
      this.setState({ loadingImage: img });
    }

    this.state = {
      loadingImage: null,
      liveImage: null
    };
  }

  componentDidMount() {
    this.loadImage();
    this.interval = setInterval(this.loadImage, this.props.interval);
  }
  componentWillUnmount() {
    clearInterval(this.interval);
  }

  render() {
    return (
      <img src={this.state.liveImage} {...this.props} />
    );
  }
}
person Rob Cannon    schedule 17.04.2018
comment
Не могли бы вы объяснить, почему это работает? Я пытаюсь сделать то же самое в React-Native. Заранее спасибо. - person Olivier MATROT; 24.04.2018
comment
@OlivierMATROT Мы можем использовать этот компонент, чтобы решить эту проблему на устройствах Android. npmjs.com/package/react-native-no-flicker-image< /а> - person Stanislav Mayorov; 17.08.2018