英文:
Run async code in nextjs component without using UseEffect
问题
在我的Next.js应用中,我有一个StrapiImage
组件,它接受来自我的Strapi后端API的图像对象作为属性。它分配了宽度、高度和URL,以及任何其他附加属性。(实际上,它只是一个常规next/image的快捷方式)
import Image from "next/image";
import { getStrapiMedia } from "../../lib/media";
export default function StrapiImage({ image, ...props }) {
return <Image src={getStrapiMedia(image)} // getStrapiMedia函数基本上只返回图像的URL。
width={image.attributes.width}
height={image.attributes.height}
alt=""
{...props} />
}
现在,我想要为这个图像添加一个模糊占位符,使用placeholder="blur"
,但由于这是外部图像,我必须在blurDataUrl
属性中提供一个base64图像。
我想要使用plaiceholder
库生成一个类似这个sollution的图像。
然而,有一个问题,为了生成图像,我需要使用await
语句。在getStaticProps
中,这不是问题,因为我可以将函数设置为async
,但我正在组件内部执行这个操作,而组件必须是普通的非异步函数。
"显而易见"的解决方案是使用useEffect
钩子,如下所示:
import Image from "next/image";
import { getStrapiMedia } from "../../lib/media";
import { useEffect, useState } from "react";
import { getPlaiceholder } from "plaiceholder";
export default function StrapiImage({ image, ...props }) {
const [blur64, setBlur64] = useState("");
useEffect(() => {
async function generatePlaceholder() {
// 在这里生成base64图像
}
generatePlaceholder();
}, []);
return <Image src={getStrapiMedia(image)}
width={image.attributes.width}
height={image.attributes.height}
alt=""
placeholder="blur"
blurDataURL={blur64}
{...props} />
}
这在技术上可以工作,但它只会在客户端运行,最终破坏了SSR和整个图像优化的目的。(特别是考虑到plaiceholder的巨大JS捆绑包)
有没有其他方法可以在不使用useEffect
的情况下仍在组件文件中完成这个操作?理想情况下,我希望它只在服务器端运行。
我正在使用nextjs@13
英文:
In my nextjs app, I have a StrapiImage
component that accepts an image object from my strapi backend api as a prop. It assigns the width, height and url + any aditional props. (It's basically a shortcut for a regular next/image)
import Image from "next/image";
import { getStrapiMedia } from "../../lib/media";
export default function StrapiImage({ image, ...props })
return <Image src={getStrapiMedia(image)} // the getStrapiMedia function basically just returns the url to the image.
width={image.attributes.width}
height={image.attributes.height}
alt=""
{...props} />
}
Now, I wanted to add a blur placeholder for this image using placeholder="blur"
but since this is an external image, I have to provided a base64 image in the blurDataUrl
prop.
I wanted to generate an image like this with the plaiceholder
library similarly to this sollution I found.
There's a problem with this though, to generate the image, I need to use an await statement. In getStaticProps
, this wouldn't be a problem as I could just make the function async
, but I'm doing this inside a component and components must regular non-async functions.
The 'obvious' sollution would be to use the useEffect
hook like so:
import Image from "next/image";
import { getStrapiMedia } from "../../lib/media";
import { useEffect, useState } from "react";
import { getPlaiceholder } from "plaiceholder";
export default function StrapiImage({ image, ...props })
const [blur64, setBlur64]
useEffect(() => {
async function generatePlaceholder() {
// generate base64 image here
}
generatePlaceholder();
}, [])
return <Image src={getStrapiMedia(image)}
width={image.attributes.width}
height={image.attributes.height}
alt=""
placeholder="blur"
blurDataURL={blur64}
{...props} />
}
This would technically work, but it would only run only on the client-side, ultimately defeating the purpose of ssr and the whole image optimisation. (Especially considering plaiceholder's huge js bundle)
Is there any other way that I could do this without useEffect
but still in the component file? Ideally, I'd like it to run only on the server-side.
I'm using nextjs@13
答案1
得分: 0
我通过使用 strapi 插件1来在后端生成占位图,而不是在前端生成,解决了这个问题。
标题中的问题仍然没有解决。在组件级别运行可预渲染的异步代码似乎不是 nextjs 官方支持的方式(特别是在页面目录中)。
以下是我找到的一些“解决方案”(主要是变通方法):
- 在页面级别生成占位图。对我来说,这意味着循环遍历我的 API 数据中的所有元素,查找图像并为它们生成占位图。这可能相当不方便,但确实有效。
- 切换到应用程序目录(如果您使用的是 next 13)。它使用了 React 服务器组件,所以在那里可以轻松实现所有这些。
- 尝试使用
useSSE
进行工作。我还没有深入研究这个,但看起来您可以使用useSSE
库在组件级别运行服务器端代码。这里有一篇文章介绍了这个方法。
英文:
I fixed the issue by using a strapi plugin to generate the placeholder image on the backend rather than on the frontend.
The issue in the title still remains unsolved though. Running pre-renderable async code at component-level doesn't seem to be officialy supported by nextjs. (with the pages directory)
Here's some "sollutions" I've found: (mostly workarounds)
-
Generate the placeholders on page-level. For me, that would mean looping through all elements in my api data looking for images and generating placeholders for them. It's pretty inconvenient but it does work.
-
Switch to the app directory. (provided you're using next 13) It uses react server components so all of this is possible and simple to do there.
-
Try to work with
useSSE
. I haven't looked into this too much but it looks like you can use theuseSSE
library to run server-side at component-level. Here's an article covering this.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论