[英]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评论反馈
https://goodreads.com
)无效图像是返回状态 404或指向实际上不是图像的资源(例如https://goodreads.com
)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:现在有两种方法可以检查图像是否有效:
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.