NextJS 13服务端Action中使用renderToStaticMarkup报错的解决方法
解决NextJS 13服务端Action中生成HTML邮件的错误及替代方案
一、修复现有代码的两个错误
1. 解决TS错误:'ResetPasswordEmail'被当作类型使用
这个错误是因为你把组件(一个值)当成了TypeScript类型来使用,比如在定义参数类型时写了const fn = (param: ResetPasswordEmail) => {}。解决步骤:
- 在
ResetPasswordEmail.tsx中单独提取并导出Props类型:
// ResetPasswordEmail.tsx type ResetPasswordEmailProps = { firstName: string; // 其他需要的props }; export default function ResetPasswordEmail({ firstName }: ResetPasswordEmailProps) { return <div>...</div>; } // 导出类型供服务端Action使用 export type { ResetPasswordEmailProps };
- 在服务端Action中使用导出的Props类型,而非组件本身:
import ResetPasswordEmail, { ResetPasswordEmailProps } from './ResetPasswordEmail'; // 用ResetPasswordEmailProps定义参数类型 async function sendEmail(userData: ResetPasswordEmailProps) { // ... }
2. 解决renderToStaticMarkup的语法错误:Expected '>', got 'firstName'
这个错误是JSX语法解析失败导致的,核心原因是服务端Action所在文件不是.tsx后缀(.ts文件默认不支持JSX)。解决步骤:
- 将服务端Action所在文件的后缀改为
.tsx,确保文件能解析JSX语法。 - 确保在
renderToStaticMarkup中正确使用JSX语法调用组件,而非函数调用:
// 正确写法 import { renderToStaticMarkup } from 'react-dom/server'; import ResetPasswordEmail from './ResetPasswordEmail'; export async function sendResetPasswordEmail() { // 用JSX语法传入props const html = renderToStaticMarkup(<ResetPasswordEmail firstName="张三" />); // 此处调用邮件发送逻辑(比如nodemailer) }
二、服务端Action发送HTML邮件的替代方案
1. 使用react-email库(推荐)
react-email专门用于构建兼容各类邮箱的React邮件模板,支持NextJS 13服务端渲染:
- 安装依赖:
npm install react-email @react-email/components @react-email/render
- 创建邮件模板组件:
// ResetPasswordEmail.tsx import { Html, Body, Container, Heading, Text, Link } from '@react-email/components'; type ResetPasswordEmailProps = { firstName: string; resetLink: string; }; export default function ResetPasswordEmail({ firstName, resetLink }: ResetPasswordEmailProps) { return ( <Html> <Body style={{ fontFamily: 'Arial, sans-serif' }}> <Container style={{ maxWidth: '600px', margin: '0 auto' }}> <Heading>Hi {firstName},</Heading> <Text>请点击下方链接重置你的密码:</Text> <Link href={resetLink} style={{ color: '#0070f3' }}> 重置密码 </Link> </Container> </Body> </Html> ); }
- 在服务端Action中渲染并发送:
import { renderAsync } from '@react-email/render'; import ResetPasswordEmail from './ResetPasswordEmail'; import nodemailer from 'nodemailer'; export async function sendResetPasswordEmailAction() { const html = await renderAsync( <ResetPasswordEmail firstName="张三" resetLink="https://your-domain.com/reset-password" /> ); // 配置邮件发送器(以nodemailer为例) const transporter = nodemailer.createTransport({ service: 'Gmail', auth: { user: 'your-email@example.com', pass: 'your-app-password', }, }); await transporter.sendMail({ from: 'your-email@example.com', to: 'user-email@example.com', subject: '重置你的密码', html: html, }); }
2. 使用第三方邮件服务的模板
比如SendGrid、Mailgun等服务,支持在后台创建邮件模板,只需在服务端Action中传入模板参数即可渲染发送,无需自己生成HTML:
- 在SendGrid后台创建模板,添加占位符(如
{{firstName}}、{{resetLink}}) - 在服务端Action中调用SendGrid API发送邮件:
import sgMail from '@sendgrid/mail'; sgMail.setApiKey('your-sendgrid-api-key'); export async function sendResetPasswordEmailAction() { await sgMail.send({ to: 'user-email@example.com', from: 'your-email@example.com', templateId: 'your-template-id', dynamicTemplateData: { firstName: '张三', resetLink: 'https://your-domain.com/reset-password', }, }); }
内容的提问来源于stack exchange,提问作者Sandy
相关产品推荐
相关产品推荐

