web-dev-qa-db-ja.com

同形/ユニバーサル反応の画像onLoadイベント-画像が読み込まれた後のイベントの登録

同形のレンダリングされたページでは、メインのscript.jsファイルの前に画像をダウンロードできます。したがって、イメージはreact register 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.jpgscript.jsより大きい

image.jpg is bigger than script.js

このシナリオでは、すべてが正常に機能しています。画像が最終的に読み込まれる前にイベントが登録されるため、コンソールにはimage loadedメッセージが表示されます。


シナリオ2-image.jpgscript.jsより小さい

image.jpg is smaller than script.js

このシナリオでは、投稿の冒頭で説明されている問題を確認できます。 onLoadイベントはトリガーされません。


質問

シナリオ2onLoadイベントをトリガーするために何ができますか?


編集:ソビエト回答実装

レンダリング時に画像の準備ができているかどうかを検出するには、純粋なjavascript completeオブジェクトのimgプロパティを確認する必要があります。

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

completeイベントを適用する前に、イメージのonloadプロパティを確認できます。

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

もう1つの方法は、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}
/>
2
Idan Gozlan

img.completeは、srcのロードが失敗した場合でもtrueです。

complete-ブラウザが画像のフェッチを終了した場合にtrueとなるブール値成功したかどうかにかかわらずを返します。画像にsrc値がない場合もtrueを示します。

  1. Imgの読み込みが成功したかどうかの決定要因としてnaturalWidthを使用します
    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();
            }
        }
    }

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

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

    render() {
        return (
            <img
                src={src}
                alt={alt}
                ref={this.myRef}
                onError={this.handleOnError}
                onLoad={this.handleOnLoad}
            />
        );
    }
  1. もう1つの方法は、componentDidMountに「チェック」イメージを追加し、それにセットeventHandlerを追加して、チェックイメージをeventListenersを処理するものにすることです。
componentDidMount() {
   const testImg = new Image();
   testImg.onerror = this.handleOnError;
   testImg.onload = this.handleImageLoaded;
   testImg.src = this.props.src; // important to set eventlisteners before src
}

1
michalhonc