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

时间:2020-03-11 10:22:47

标签: javascript html css reactjs

想象一下我想创建一个组件来渲染图像。如果图像资源有效,则应通过css background-image将其渲染为div。否则,我应该将其渲染为带有alt标签的标准<img>

所以我们得到这样的东西:

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

在这里,我们首先通过简单的javascript(在useEffect中)开始对图像进行抓取。如果有效,资源(由浏览器)将被缓存,并且随后的<div>的呈现是瞬时的。

但是,如果资源无效,则没有适当的缓存机制(有关更多详细信息,请参见this question)。因此,当我们在Component的末尾呈现新的<img>元素时,它会启动一个全新的请求以获取该图像(尽管推断该图像已损坏)。

因此,为了避免重复获取,一种可能的解决方案是呈现已经初始化的image元素,而不是呈现该图像的新的react元素。

这可能吗?


评论反馈

  • 无效图像是指返回状态404 或指向实际上不是图像的资源(例如https://goodreads.com
  • 我想在浏览器默认的“损坏的图像”损坏的情况下显示它。这无法通过background-image CSS完成,因此我需要依赖标准的<img>元素。因为我已经确定图像已损坏(在useEffect中),所以我想在React中渲染损坏的<img>时避免新的获取。

希望可以澄清一切!

1 个答案:

答案 0 :(得分:1)

有效的定义是:图像已加载,并且宽度和高度都大于零。

现在有两种方法可以检查图像是否有效:

  • 假设图片无效,请尝试加载图片,检查图片是否有效,然后呈现图片标签。
  • 假定图像有效,渲染img标签,然后检查图像是否有效。

以下代码将首先假定图像无效

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

用法:

<ImageComponent src="IMAGE_URL" />

以下代码将首先假定图像有效

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

用法:

<ImageComponent src="IMAGE_URL" />
相关问题