Изображение onLoad событие в изоморфном/универсальном реагировании - регистрирует событие после загрузки изображения

В изоморфной отрисовке страницы изображение можно скачать перед основным файлом script.js. Таким образом, изображение может быть уже загружено до react регистр onLoad события - не вызвать это событие.

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} />
    );
}

Сценарий 1 - image.jpg больше, чем script.js

image.jpg is bigger than script.js

В этом сценарии все работает нормально. Событие регистрируется до окончательной загрузки изображения, поэтому в консоли image loaded сообщение image loaded.


Сценарий 2 - image.jpg меньше, чем script.js

image.jpg is smaller than script.js

В этом сценарии вы можете увидеть проблему, описанную в начале поста. Событие onLoad не вызывается.


Вопрос

Что я могу сделать, чтобы вызвать событие onLoad в сценарии 2?


РЕДАКТИРОВАТЬ: Совиуть ответ реализации

Чтобы определить, готово ли изображение при рендеринге, вы должны проверить свойство complete на чистом объекте img javascript:

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} />
    );
}

Ответ 1

Вы можете проверить свойство complete на изображении перед применением события onload.

if (!img.complete) {
    // add onload listener here
}

Ответ 2

Другой способ - использовать ref и покрыть эти оба сценария:

<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}
/>

Ответ 3

img.complete верно даже в случае сбоя загрузки src.

complete - возвращает логическое значение, которое имеет значение true, если браузер завершил выборку изображения, независимо от того, успешно оно или нет. Это также показывает true, если изображение не имеет значения src.

  1. Используйте naturalWidth в качестве определяющего, была ли загрузка IMG успешной или нет

    state = {isLoading: true, hasError: false,}

    myRef = React.createRef();

    componentDidMount() {const img = this.myRef.current;

    if (img && img.complete) {
        if (img.naturalWidth === 0) {
            this.handleOnError();
        } else {
            this.handleImageLoaded();
        }
    }
    
    if (img && img.complete) {
        if (img.naturalWidth === 0) {
            this.handleOnError();
        } else {
            this.handleImageLoaded();
        }
    }
    

    handleImageLoaded =() => {if (this.state.isLoading) {this.setState({isLoading: false}); }}

    handleOnError =() => {this.setState({hasError: true}); }

    render() {return(); }

Ответ 4

<img
    src={this.props.imageUrl}
    onLoad={this.handleImageLoaded.bind(this)}
    onError={this.handleImageErrored.bind(this)}
/>