在 NextJS 中使用后备图像的最佳方式是什么?
What is the best way to have a fallback image in NextJS?
最近在NextJS做一个项目,使用YoutubeAPI获取视频信息,包括缩略图URLs。
全分辨率图片的缩略图 URL 如下所示:
https://i.ytimg.com/vi/${videoId}/maxresdefault.jpg
但是,有时 YouTube 无法生成全分辨率图像,在这种情况下,图像不会显示在我的网页上。
如果带有 URL https://i.ytimg.com/vi/${videoId}/maxresdefault.jpg
的图像不存在我希望使用另一个 URL 比如 https://i.ytimg.com/vi/${videoId}/hqdefault.jpg
使用 next/image
处理此问题的最佳方法是什么?
您可以创建一个自定义图像组件来扩展内置 next/image
并在图像加载失败时通过触发 onError
回调添加回退逻辑。
import React, { useState } from 'react';
import Image from 'next/image';
const ImageWithFallback = (props) => {
const { src, fallbackSrc, ...rest } = props;
const [imgSrc, setImgSrc] = useState(src);
return (
<Image
{...rest}
src={imgSrc}
onError={() => {
setImgSrc(fallbackSrc);
}}
/>
);
};
export default ImageWithFallback;
那么,可以直接使用自定义组件代替next/image
如下:
<ImageWithFallback
key={videoId}
layout="fill"
src={`https://i.ytimg.com/vi/${videoId}/maxresdefault.jpg`}
fallbackSrc={`https://i.ytimg.com/vi/${videoId}/hqdefault.jpg`}
/>
传递 key
道具以在 videoId
更改时触发重新渲染。
@juliomalves 给出了 99% 的答案,但我想补充一下。
在他的解决方案中更改 src 时出现问题,因为图像不会更新,因为它正在获取未更新的 imgSrc 值。这是我对他的回答的补充:
import React, { useState } from 'react';
import Image from 'next/image';
const ImageFallback = (props) => {
const { src, fallbackSrc, ...rest } = props;
const [imgSrc, setImgSrc] = useState(false);
const [oldSrc, setOldSrc] = useState(src);
if (oldSrc!==src)
{
setImgSrc(false)
setOldSrc(src)
}
return (
<Image
{...rest}
src={imgSrc?fallbackSrc:src}
onError={() => {
setImgSrc(true);
}}
/>
);
};
export default ImageFallback;
现在 imgSrc 仅用作标志,并且跟踪 src 值,这有助于更改图像,即使您的图像之前有备用图像。
这些答案很有帮助,但有一种方法可以利用 useEffect
钩子来实现这一点,而无需每次都传递 key
:
useEffect(() => {
set_imgSrc(src);
}, [src]);
此外,onError
事件似乎不会针对某些图像触发(我相信 layout='fill'
在某些情况下不会触发它),对于那些我一直在使用的情况onLoadingComplete
然后我检查图像的宽度是否为 0
onLoadingComplete={(result) => {
if (result.naturalWidth === 0) { // Broken image
set_imgSrc(fallbackSrc);
}
}}
完整代码:
import Image from "next/image";
import { useEffect, useState } from "react";
export default function ImageFallback({ src, fallbackSrc, ...rest }) {
const [imgSrc, set_imgSrc] = useState(src);
useEffect(() => {
set_imgSrc(src);
}, [src]);
return (
<Image
{...rest}
src={imgSrc}
onLoadingComplete={(result) => {
if (result.naturalWidth === 0) {
// Broken image
set_imgSrc(fallbackSrc);
}
}}
onError={() => {
set_imgSrc(fallbackSrc);
}}
/>
);
}
最近在NextJS做一个项目,使用YoutubeAPI获取视频信息,包括缩略图URLs。
全分辨率图片的缩略图 URL 如下所示:
https://i.ytimg.com/vi/${videoId}/maxresdefault.jpg
但是,有时 YouTube 无法生成全分辨率图像,在这种情况下,图像不会显示在我的网页上。
如果带有 URL https://i.ytimg.com/vi/${videoId}/maxresdefault.jpg
的图像不存在我希望使用另一个 URL 比如 https://i.ytimg.com/vi/${videoId}/hqdefault.jpg
使用 next/image
处理此问题的最佳方法是什么?
您可以创建一个自定义图像组件来扩展内置 next/image
并在图像加载失败时通过触发 onError
回调添加回退逻辑。
import React, { useState } from 'react';
import Image from 'next/image';
const ImageWithFallback = (props) => {
const { src, fallbackSrc, ...rest } = props;
const [imgSrc, setImgSrc] = useState(src);
return (
<Image
{...rest}
src={imgSrc}
onError={() => {
setImgSrc(fallbackSrc);
}}
/>
);
};
export default ImageWithFallback;
那么,可以直接使用自定义组件代替next/image
如下:
<ImageWithFallback
key={videoId}
layout="fill"
src={`https://i.ytimg.com/vi/${videoId}/maxresdefault.jpg`}
fallbackSrc={`https://i.ytimg.com/vi/${videoId}/hqdefault.jpg`}
/>
传递 key
道具以在 videoId
更改时触发重新渲染。
@juliomalves 给出了 99% 的答案,但我想补充一下。 在他的解决方案中更改 src 时出现问题,因为图像不会更新,因为它正在获取未更新的 imgSrc 值。这是我对他的回答的补充:
import React, { useState } from 'react';
import Image from 'next/image';
const ImageFallback = (props) => {
const { src, fallbackSrc, ...rest } = props;
const [imgSrc, setImgSrc] = useState(false);
const [oldSrc, setOldSrc] = useState(src);
if (oldSrc!==src)
{
setImgSrc(false)
setOldSrc(src)
}
return (
<Image
{...rest}
src={imgSrc?fallbackSrc:src}
onError={() => {
setImgSrc(true);
}}
/>
);
};
export default ImageFallback;
现在 imgSrc 仅用作标志,并且跟踪 src 值,这有助于更改图像,即使您的图像之前有备用图像。
这些答案很有帮助,但有一种方法可以利用 useEffect
钩子来实现这一点,而无需每次都传递 key
:
useEffect(() => {
set_imgSrc(src);
}, [src]);
此外,onError
事件似乎不会针对某些图像触发(我相信 layout='fill'
在某些情况下不会触发它),对于那些我一直在使用的情况onLoadingComplete
然后我检查图像的宽度是否为 0
onLoadingComplete={(result) => {
if (result.naturalWidth === 0) { // Broken image
set_imgSrc(fallbackSrc);
}
}}
完整代码:
import Image from "next/image";
import { useEffect, useState } from "react";
export default function ImageFallback({ src, fallbackSrc, ...rest }) {
const [imgSrc, set_imgSrc] = useState(src);
useEffect(() => {
set_imgSrc(src);
}, [src]);
return (
<Image
{...rest}
src={imgSrc}
onLoadingComplete={(result) => {
if (result.naturalWidth === 0) {
// Broken image
set_imgSrc(fallbackSrc);
}
}}
onError={() => {
set_imgSrc(fallbackSrc);
}}
/>
);
}