如何在 NextJS 服务器操作中使用 renderToStaticMarkup

How to use renderToStaticMarkup in NextJS server action

提问人:Sandy 提问时间:10/23/2023 最后编辑:Sandy 更新时间:10/28/2023 访问量:118

问:

我正在尝试在 NextJS 13 服务器操作中使用以通过电子邮件发送生成的 HTML。renderToStaticMarkup

import { renderToStaticMarkup } from "react-dom/server";
import { sendEmail } from "@/infra/email";
import { ResetPasswordEmail } from "@/infra/email/templates";
import { userRoutes } from "@/routes";

interface SendPasswordResetLink {
  email: string;
  firstName: string;
  passwordResetToken: string;
}

export const sendPasswordResetLink = async ({ email, firstName, passwordResetToken }: SendPasswordResetLink): Promise<void> => {
  const url = userRoutes.resetPassword.generateUrl(passwordResetToken);
  const subject = `Password reset`;
  const html = renderToStaticMarkup(<ResetPasswordEmail firstName={firstName} url={url} />);
  const result = await sendEmail({ html, subject, toEmail: email, toName: firstName });

  //... more code
};

但是,我在后端收到以下错误:Error: × Expected '>', got 'firstName'

在 VSCode 中,我得到红色的波浪线,当我悬停时,它说:'ResetPasswordEmail' refers to a value, but is being used as a type here. Did you mean 'typeof ResetPasswordEmail'?ts(2749)

enter image description here

该组件没有任何交互性,其文件名以 结尾。ResetPasswordEmail.tsx

知道如何解决这个问题,或者以其他方式在服务器操作中发送HTML电子邮件吗?谢谢!

reactjs next.js next.js13 服务器操作

评论

0赞 OlegWock 10/26/2023
带功能的文件的扩展名是什么?sendPasswordResetLink
0赞 Sandy 10/26/2023
我试过了,在两者中都遇到了相同的错误。.ts.tsx

答:

0赞 libra 10/27/2023 #1

该错误可能是由于 nodejs 无法识别 JSX 语法引起的。尝试改用 React.createElement。

const element = React.createElement(ResetPasswordEmail, {firstName, url})
const html = renderToStaticMarkup(element)

建议:

由于您使用 NextJS 进行 SSR,也许最好让 NextJS 处理渲染,然后您可以向 NextJS 服务器发出请求以获取渲染的 HTML 并通过电子邮件发送。

0赞 livealvi 10/28/2023 #2

您看到的错误可能是由于 TypeScript 类型错误造成的。

当您在函数中使用组件时,TypeScript 会将其视为值而不是类型。<ResetPasswordEmail>renderToStaticMarkup

要修复此错误,您可以尝试使用 typeof 关键字将组件导入为类型。ResetPasswordEmail

下面是一个示例:

import { renderToStaticMarkup } from "react-dom/server";
import { sendEmail } from "@/infra/email";
import { ResetPasswordEmail } from "@/infra/email/templates";
import { userRoutes } from "@/routes";

interface SendPasswordResetLink {
  email: string;
  firstName: string;
  passwordResetToken: string;
}

export const sendPasswordResetLink = async ({ email, firstName, passwordResetToken }: SendPasswordResetLink): Promise<void> => {
  const url = userRoutes.resetPassword.generateUrl(passwordResetToken);
  const subject = `Password reset`;
  const html = renderToStaticMarkup(<typeof ResetPasswordEmail>{ firstName, url });
  const result = await sendEmail({ html, subject, toEmail: email, toName: firstName });

  //... more code
};

此示例使用 typeof 关键字将组件导入为类型。还使用对象速记符号将 and props 直接传递给组件。ResetPasswordEmailfirstNameurl

您也可以尝试使用该函数代替 . 是一个服务器端呈现函数,旨在与 Next.js 一起使用。renderToStringrenderToStaticMarkuprenderToString

这是:

import { renderToString } from "react-dom/server";
import { sendEmail } from "@/infra/email";
import { ResetPasswordEmail } from "@/infra/email/templates";
import { userRoutes } from "@/routes";

interface SendPasswordResetLink {
  email: string;
  firstName: string;
  passwordResetToken: string;
}

export const sendPasswordResetLink = async ({ email, firstName, passwordResetToken }: SendPasswordResetLink): Promise<void> => {
  const url = userRoutes.resetPassword.generateUrl(passwordResetToken);
  const subject = `Password reset`;
  const html = renderToString(<ResetPasswordEmail firstName={firstName} url={url} />);
  const result = await sendEmail({ html, subject, toEmail: email, toName: firstName });

  //... more code
};

在此示例中,使用该函数将组件呈现为字符串。还使用对象速记符号将 and props 直接传递给组件。renderToStringResetPasswordEmailfirstNameurl