在Serverless React中用dangerouslySetInnerHTML渲染S3文件报错
问题根源
React的dangerouslySetInnerHTML必须接收一个带__html属性的对象,你用异步函数createPageBody的时候,直接把函数返回值传进去了——但异步函数默认返回的是Promise,不是最终的HTML内容,组件渲染时拿到的是未完成的Promise,自然触发了invariant=61错误;同步函数createPageBodyTest直接返回{__html: '测试内容'}这种合规对象,所以没毛病。
解决办法
得用React状态来管理异步获取的HTML内容,步骤如下:
- 初始化状态存HTML内容,默认值要符合
dangerouslySetInnerHTML的要求,比如{__html: ''} - 在组件的
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
相关产品推荐
相关产品推荐

