javascript - How to conditionally render an image in React? - Stack Overflow

Imagine that I want to create a ponent to render an image. If the image resource is valid, I should ren

Imagine that I want to create a ponent to render an image. If the image resource is valid, I should render it into a div via css background-image. Otherwise I should render it as a standard <img> with an alt tag.

So we get something like this:

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

  useEffect(() => {
    const image = new Image();
    image.onsuccess = () => {
      setLoaded(true);
      setRenderFallback(false);
    }
    image.onerror = () => {
      setLoaded(true);
      setRenderFallback(true);
    }
    image.src = src;

    return () => {
      // clean up listeners
      image.onsuccess = undefined;
      image.onerror = undefined;
    }
  }, [src]);

  if (!loaded) { return null; }

  return renderFallback ?
    <div style={{backgroundImage: `url(${src})`}}/> :
    <img src={src} alt="my alt"/>;
}

Here, we first kick off a fetch for the image via plain javascript (within useEffect). If it's valid, the resource is cached (by the browser), and the rendering of the subsequent <div> is instantaneous.

However, if the resource is not valid, then there is no caching mechanism in place (see this question for more details). And so when we render the new <img> element at the end of the Component, it kicks off a brand new request to fetch that image (despite deducing that it's broken already).

So, to avoid this duplicate fetching, a possible solution would be to render the already-initialized image element, rather than a new react element to represent that image.

Is this possible?


Feedback from ments

  • An invalid image is one that returns a status of 404, or points to a resource that's not actually an image (e.g. )
  • I would like to display the browser's default 'broken image' in cases where it's broken. This can't be done via background-image css, so I need to rely on a standard <img> element. As I've already determined that the image is broken (in useEffect), I'd like to avoid a new fetch when I'm rendering the broken <img> in React.

Hope that clarifies things!

Imagine that I want to create a ponent to render an image. If the image resource is valid, I should render it into a div via css background-image. Otherwise I should render it as a standard <img> with an alt tag.

So we get something like this:

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

  useEffect(() => {
    const image = new Image();
    image.onsuccess = () => {
      setLoaded(true);
      setRenderFallback(false);
    }
    image.onerror = () => {
      setLoaded(true);
      setRenderFallback(true);
    }
    image.src = src;

    return () => {
      // clean up listeners
      image.onsuccess = undefined;
      image.onerror = undefined;
    }
  }, [src]);

  if (!loaded) { return null; }

  return renderFallback ?
    <div style={{backgroundImage: `url(${src})`}}/> :
    <img src={src} alt="my alt"/>;
}

Here, we first kick off a fetch for the image via plain javascript (within useEffect). If it's valid, the resource is cached (by the browser), and the rendering of the subsequent <div> is instantaneous.

However, if the resource is not valid, then there is no caching mechanism in place (see this question for more details). And so when we render the new <img> element at the end of the Component, it kicks off a brand new request to fetch that image (despite deducing that it's broken already).

So, to avoid this duplicate fetching, a possible solution would be to render the already-initialized image element, rather than a new react element to represent that image.

Is this possible?


Feedback from ments

  • An invalid image is one that returns a status of 404, or points to a resource that's not actually an image (e.g. https://goodreads.)
  • I would like to display the browser's default 'broken image' in cases where it's broken. This can't be done via background-image css, so I need to rely on a standard <img> element. As I've already determined that the image is broken (in useEffect), I'd like to avoid a new fetch when I'm rendering the broken <img> in React.

Hope that clarifies things!

Share Improve this question edited Mar 12, 2020 at 13:46 Daniele Molinari 6217 silver badges30 bronze badges asked Mar 11, 2020 at 10:22 Shane CallananShane Callanan 5414 silver badges13 bronze badges 5
  • 1 Hi, could you explain a bit what you call an invalid image? Is this an image that you want to upload? – t3__rry Commented Mar 11, 2020 at 10:27
  • User React.memo() to avoid unwanted re render of ponents. Refer the link for more details scotch.io/tutorials/… – Akhil Aravind Commented Mar 11, 2020 at 10:29
  • Not sure what your trying to do here, The 404 will still take time. If your saying this 404 is always going to be invalid and you want to cache it that way. Then what you could do is use localeStorage to flag this url as invalid.. – Keith Commented Mar 11, 2020 at 10:33
  • @t3__rry This is related to the other question I linked. An invalid image would be one that points to a non-image resource (e.g. https://goodreads.), or one that returns a status of 404 – Shane Callanan Commented Mar 11, 2020 at 10:38
  • I believe I understand what your after, your React code looks like it's not far off, your not passing props but src, so that doesn't make sense but apart from that it looks like with a bit of modification you could get this do what your after using Session/LocaleStorage, with options to even put in custom expiry dates etc. If you could knock up a snippet, I could alter it. – Keith Commented Mar 11, 2020 at 10:46
Add a ment  | 

1 Answer 1

Reset to default 2

My definition of valid is: the image has been loaded and it has both a width and a height greater than zero.

Now there are two ways you check if an image is valid:

  • Assume the image is not valid, try loading the image, check if it is valid, then render the image tag.
  • Assume the image is valid, render the img tag, then check if the image is valid.

The following code will first assume that the image is not valid.

import React, { useEffect, useRef, useState } from "react";

const ImageComponent = ({src}) => {
    const container = useRef(null);
    const [valid, setValid] = useState(false);

    useEffect(() => {
        container.current.innerHTML = '';

        const image = new Image();

        const checkValid = () => {
            if (image.plete && image.naturalWidth > 0 && image.naturalHeight > 0) {
                setValid(true);
                container.current.appendChild(image);
            }
        }

        image.onload = checkValid;
        image.src = src;
    }, [src]);

    return (
        <div>
          <div ref={container} />
          {!valid && <div>Image not valid</div>}
        </div>
    );
};

Usage:

<ImageComponent src="IMAGE_URL" />

The following code will first assume that the image is valid.

import React, { useRef, useState } from 'react';

const ImageComponent = ({src}) => {
    const image = useRef(null);
    const [valid, setValid] = useState(true);

    const checkValid = () => {
        if (!image.current.plete || image.current.naturalWidth < 1 || image.current.naturalHeight < 1) setValid(false);
    }

    if (valid) {
        return (
            <img
                src={src}
                onLoad={checkValid}
                onError={() => setValid(false)}
                ref={image} 
            />
        );
    }

    return <div>Image not valid</div>;
};

Usage:

<ImageComponent src="IMAGE_URL" />

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745298803a4621307.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信