Wie erkennt man, wann ein Bild geladen wird, das über Requisiten bereitgestellt wird, und ändert den Status in React?

Lesezeit: 5 Minuten

Benutzeravatar von Sergio Jimenez Corominas
Sergio Jimenez Corominas

Ich möchte ein anderes Bild (falschen Avatar) laden, während das endgültige Avatar-Bild geladen wird. Die Idee besteht darin, zu erkennen, wann das Requisitenbild geladen ist, und einen Status zu ändern. Ist es möglich? Einige Ideen? Danke schön!

class ImageUser extends React.Component {

constructor(props) {
    super(props);
    this.state = {userImageLoaded: false};
    let imageSrc = "";

    if (!this.props.userImage) {
        imageSrc = this.props.noUserImage;
    } else {
        imageSrc = this.props.userImage;
    }

    this.loadingImage = <img className={styles.imageUser}
                     src={this.props.loadingImage} alt="2"/>;

    this.userImage =
        <img onLoad={this.setState({userImageLoaded: true})}
             className={styles.imageUser} src={imageSrc}
             alt="1"/>;

}

render() {
    let image = "";
    if (this.state.userImageLoaded) {
        image = this.userImage;
    } else {
        image = this.loadingImage;
    }
    return (
        <div>
            {image}
        </div>
    );
}
}

export default ImageUser;

Es gibt mehrere Möglichkeiten, dies zu tun, aber die einfachste besteht darin, das endgültige Bild ausgeblendet anzuzeigen und es dann sichtbar zu machen, sobald es geladen ist.

JSBin-Demo

class Foo extends React.Component {
  constructor(){
    super();
    this.state = {loaded: false};
  }

  render(){
    return (
      <div>
        {this.state.loaded ? null :
          <div
            style={{
              background: 'red',
              height: '400px',
              width: '400px',
            }}
          />
        }
        <img
          style={this.state.loaded ? {} : {display: 'none'}}
          src={this.props.src}
          onLoad={() => this.setState({loaded: true})}
        />
      </div>
    );
  }
}

  • Genau das suche ich. Das ist der einfachste Weg. Es gibt noch ein anderes Problem, das auf die Komponente wartet, aber das ist ein anderes Thema 🙂

    – Sergio Jimenez Corominas

    30. März 2017 um 13:17 Uhr

  • Wie können wir so etwas erstellen, damit mehrere Bilder in einer Schleife geladen werden?

    – Ranjith

    18. Okt. 2017 um 17:27 Uhr

  • @Ranjith Sie würden eine Zuordnung von ID/SRC-Werten zu Booleschen Werten speichern, die angeben, ob sie geladen wurden.

    – Räuber

    19. Okt. 2017 um 9:41

  • @Ranjith, Sie könnten eine separate „Bild“-Komponente erstellen, damit sie ihren eigenen Status hat. Dann müssen Sie sich keine Gedanken über die Schlüssel-/ID-Zuordnung machen.

    Benutzer723505

    9. Juni 2018 um 18:17 Uhr

  • @FakeRainBrigand Danke, was ist mit Hintergrundbildern? <div style={{ backgroundImage: 'url(${url})' }} />?

    – Zünder

    21. Dezember 2018 um 14:35 Uhr


Dieselbe Antwort wie Brigands akzeptierte Antwort, jedoch mit Hooks:

const Foo = ({ src }) => {
  const [loaded, setLoaded] = useState(false);

  return (
    <div>
      {loaded ? null : (
        <div
          style={{
            background: 'red',
            height: '400px',
            width: '400px'
          }}
        />
      )}
      <img
        style={loaded ? {} : { display: 'none' }}
        src={src}
        onLoad={() => setLoaded(true)}
      />
    </div>
  );
};

Dieselbe Idee mit Verweis auf das Element, aber Verwendung von Funktionskomponenten und Hooks mit Typoskript:

import React from 'react';

export const Thumbnail = () => {
  const imgEl = React.useRef<HTMLImageElement>(null);
  const [loaded, setLoaded] = React.useState(false);

  const onImageLoaded = () => setLoaded(true);

  React.useEffect(() => {
    const imgElCurrent = imgEl.current;

    if (imgElCurrent) {
      imgElCurrent.addEventListener('load', onImageLoaded);
      return () => imgElCurrent.removeEventListener('load', onImageLoaded);
    }
  }, [imgEl]);

  return (
    <>
      <p style={!loaded ? { display: 'block' } : { display: 'none' }}>
        Loading...
      </p>
      <img
        ref={imgEl}
        src="https://via.placeholder.com/60"
        alt="a placeholder"
        style={loaded ? { display: 'inline-block' } : { display: 'none' }}
      />
    </>
  );
};

Benutzer-Avatar von NearHuscarl
NearHuscarl

Sie können noch einen Schritt weiter gehen, indem Sie beim Bildwechsel einen Einblendübergang hinzufügen. Der Code unten ist mein CrossFadeImage Komponente. Kopieren Sie es einfach und verwenden Sie es anstelle des Normalen img Komponente.

Der CrossFadeImage hat 2 Bilder, top Und bottom. bottom darauf gestapelt ist top und wird verwendet, um das Bild anzuzeigen, das animiert werden muss, in diesem Fall das alte Bild, das beim Umschalten ausgeblendet wird.

Im Ruhezustand, top zeigt das aktuelle Bild an bottom ist das vorherige Bild, aber in transparent

CrossFadeImage wird beim Erkennen die folgenden Dinge tun props.src Änderungen

  • Setzen Sie beide SRCs zurück, um alle aktuell laufenden Animationen abzubrechen
  • Satz top‘s src zum neuen Bild und bottomist die Quelle des aktuellen Bildes, das im nächsten Frame ausgeblendet wird
  • Satz bottom auf transparent, um den Übergang einzuleiten
import React from "react";

const usePrevious = <T extends any>(value: T) => {
  const ref = React.useRef<T>();
  React.useEffect(() => {
    ref.current = value;
  }, [value]);
  return ref.current;
};
const useRequestAnimationFrame = (): [(cb: () => void) => void, Function] => {
  const handles = React.useRef<number[]>([]);
  const _raf = (cb: () => void) => {
    handles.current.push(requestAnimationFrame(cb));
  };
  const _resetRaf = () => {
    handles.current.forEach((id) => cancelAnimationFrame(id));
    handles.current = [];
  };

  return [_raf, _resetRaf];
};

type ImageProps = {
  src: string;
  alt?: string;
  transitionDuration?: number;
  curve?: string;
};

const CrossFadeImage = (props: ImageProps) => {
  const { src, alt, transitionDuration = 0.35, curve = "ease" } = props;
  const oldSrc = usePrevious(src);
  const [topSrc, setTopSrc] = React.useState<string>(src);
  const [bottomSrc, setBottomSrc] = React.useState<string>("");
  const [bottomOpacity, setBottomOpacity] = React.useState(0);
  const [display, setDisplay] = React.useState(false);
  const [raf, resetRaf] = useRequestAnimationFrame();

  React.useEffect(() => {
    if (src !== oldSrc) {
      resetRaf();
      setTopSrc("");
      setBottomSrc("");

      raf(() => {
        setTopSrc(src);
        setBottomSrc(oldSrc!);
        setBottomOpacity(99);

        raf(() => {
          setBottomOpacity(0);
        });
      });
    }
  });

  return (
    <div
      className="imgContainer"
      style={{
        position: "relative",
        height: "100%"
      }}
    >
      {topSrc && (
        <img
          style={{
            position: "absolute",
            opacity: display ? "100%" : 0,
            transition: `opacity ${transitionDuration}s ${curve}`
          }}
          onLoad={() => setDisplay(true)}
          src={topSrc}
          alt={alt}
        />
      )}
      {bottomSrc && (
        <img
          style={{
            position: "absolute",
            opacity: bottomOpacity + "%",
            transition: `opacity ${transitionDuration}s ${curve}`
          }}
          src={bottomSrc}
          alt={alt}
        />
      )}
    </div>
  );
};

export default CrossFadeImage;

Verwendung

<CrossFadeImage
  src={image}
  alt="phonee"
  transitionDuration={0.35}
  curve="ease-in-out"
/>

Live-Demo

Bearbeiten Sie die Demo-App auf CodeSandbox

https://stackoverflow.com/a/43115422/9536897 ist nützlich, danke.

Ich möchte dich stärken und ergänzen
Für Hintergrundbild

  constructor(){
    super();
    this.state = {loaded: false};
  }

  render(){
    return (
      <div>
        {this.state.loaded ? null :
          <div
            style={{
              background: 'red',
              height: '400px',
              width: '400px',
            }}
          />
        }
        <img
          style={{ display: 'none' }}
          src={this.props.src}
          onLoad={() => this.setState({loaded: true})}
        />
       <div 
         style={ {
                  background: `url(${this.props.src})`
                   ,display: this.state.loaded?'none':'block'
                }}
        />
      </div>
    );
  }
}```

Eine bessere Möglichkeit zu erkennen, wann ein Bild geladen wird, besteht darin, einen Verweis auf das Element zu erstellen und dann einen Ereignis-Listener zum Verweis hinzuzufügen. Sie können das Hinzufügen von Event-Handler-Code in Ihrem Element vermeiden und die Lesbarkeit Ihres Codes wie folgt verbessern:

    class Foo extends React.Component {
        constructor(){
            super();
            this.state = {loaded: false};
            this.imageRef = React.createRef();
        }

        componentDidMount() {
            this.imageRef.current.addEventListener('load', onImageLoad);
        }

        onImageLoad = () => { 
            this.setState({loaded: true})
        }

        render(){
            return (
              <div>
                {this.state.loaded ? null :
                  <div
                    style={{
                      background: 'red',
                      height: '400px',
                      width: '400px',
                    }}
                  />
                }
                <img
                  ref={this.imageRef}
                  style={{ display: 'none' }}
                  src={this.props.src}
                />
                <div 
                  style={{
                      background: `url(${this.props.src})`
                      ,display: this.state.loaded?'none':'block'
                  }}
                />
              </div>
            );
        }
    }

Akzeptierte Antwort mit Rückenwind

const [isImageLoaded, setIsImageLoaded] = useState(false)     

{!isImageLoaded && <img width={30} src="https://stackoverflow.com/images/spinner.svg" />}

        <img
          className={`mx-4 ${!isImageLoaded && 'hidden'}`}
          width={30}
          src="imageUrl"
          onLoad={() => setIsImageLoaded(true)}
        />

1453820cookie-checkWie erkennt man, wann ein Bild geladen wird, das über Requisiten bereitgestellt wird, und ändert den Status in React?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy