简体   繁体   English

如何在 React 中有条件地渲染图像?

[英]How to conditionally render an image in React?

Imagine that I want to create a component to render an image.想象一下,我想创建一个组件来渲染图像。 If the image resource is valid, I should render it into a div via css background-image .如果图像资源有效,我应该通过 css background-image将它渲染到一个 div 中。 Otherwise I should render it as a standard <img> with an alt tag.否则我应该将它呈现为带有 alt 标签的标准<img>

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).在这里,我们首先通过普通的 javascript(在 useEffect 中)启动对图像的获取。 If it's valid, the resource is cached (by the browser), and the rendering of the subsequent <div> is instantaneous.如果有效,则资源被缓存(由浏览器),后续<div>的渲染是即时的。

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).因此,当我们在组件末尾渲染新的<img>元素时,它会启动一个全新的请求来获取该图像(尽管推断它已经损坏了)。

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.因此,为了避免这种重复获取,一个可能的解决方案是渲染已经初始化的image元素,而不是一个新的反应元素来表示该图像。

Is this possible?这可能吗?


Feedback from comments评论反馈

  • An invalid image is one that returns a status of 404 , or points to a resource that's not actually an image (eg https://goodreads.com )无效图像是返回状态 404或指向实际上不是图像的资源(例如https://goodreads.com
  • 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.这不能通过background-image css 来完成,所以我需要依赖一个标准的<img>元素。 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.由于我已经确定图像已损坏(在 useEffect 中),因此当我在 React 中渲染损坏的<img>时,我想避免进行新的获取。

Hope that clarifies things!希望能澄清事情!

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.假设图片有效,渲染img标签,然后检查图片是否有效。

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.complete && 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.complete || 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" />

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM