You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Serverless React中用dangerouslySetInnerHTML渲染S3文件报错

问题根源

React的dangerouslySetInnerHTML必须接收一个带__html属性的对象,你用异步函数createPageBody的时候,直接把函数返回值传进去了——但异步函数默认返回的是Promise,不是最终的HTML内容,组件渲染时拿到的是未完成的Promise,自然触发了invariant=61错误;同步函数createPageBodyTest直接返回{__html: '测试内容'}这种合规对象,所以没毛病。

解决办法

得用React状态来管理异步获取的HTML内容,步骤如下:

  1. 初始化状态存HTML内容,默认值要符合dangerouslySetInnerHTML的要求,比如{__html: ''}
  2. 在组件的useEffect(类组件用componentDidMount)里调用异步函数拿S3内容,拿到后更新状态

函数组件示例代码

import { useState, useEffect } from 'react';
import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';

// 初始化S3客户端,替换成你的区域
const s3Client = new S3Client({ region: 'us-east-1' });

const S3HtmlPage = () => {
  // 初始状态必须是带__html的对象,避免渲染报错
  const [htmlContent, setHtmlContent] = useState({ __html: '' });

  useEffect(() => {
    const getS3Html = async () => {
      try {
        const cmd = new GetObjectCommand({
          Bucket: '你的存储桶名称',
          Key: '目标HTML文件的路径'
        });
        const res = await s3Client.send(cmd);
        // 把S3返回的流转成字符串
        const rawHtml = await res.Body.transformToString();
        // 更新状态,传入合规的对象
        setHtmlContent({ __html: rawHtml });
      } catch (err) {
        console.error('拉取S3文件失败:', err);
        // 出错时显示 fallback 内容
        setHtmlContent({ __html: '<p>页面加载失败</p>' });
      }
    };

    getS3Html();
  }, []); // 空依赖确保只在组件挂载时执行一次

  return <div dangerouslySetInnerHTML={htmlContent} />;
};

export default S3HtmlPage;

核心注意事项

  • 异步逻辑绝对不能直接写在渲染阶段,必须放在副作用钩子(useEffect/ componentDidMount)里,不然要么无限渲染,要么给dangerouslySetInnerHTML传个Promise,直接报错
  • 不管初始状态还是更新后的状态,都得是带__html属性的对象,不能直接传字符串或者其他类型
  • S3返回的响应体是流对象,得用transformToString()转成字符串再用
为啥同步函数没问题?

同步函数createPageBodyTest直接返回了dangerouslySetInnerHTML需要的格式,组件渲染时能直接拿到正确的对象,自然不会触发错误;而异步函数返回的是Promise,React根本没法把它解析成需要的格式,所以报错。

内容的提问来源于stack exchange,提问作者NealWalters

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 22:01:01