JSX 字符串转 React Element 的几种方案
目录
在 React 项目中,有时我们需要处理 JSX 字符串并将其转换为真正的 React 元素,比如从 CMS 获取模板或构建可视化编辑器时。本文介绍三种实用方案及其优缺点。
1. react-jsx-parser:安全简单型
react-jsx-parser 是一个简单安全的方案,
import JsxParser from 'react-jsx-parser';
<JsxParser jsx="<div>Hello</div>" components={{ MyComponent }} />
优势:
- 配置简单,安装即用
- 不执行函数定义(有效防 XSS 攻击)
- 支持白名单组件,可控性好
缺点:
- 不支持函数声明 (
function xxx(){}
) - 逻辑表达式支持有限
- 动态性较弱,复杂场景力不从心
适合场景:
渲染小型 JSX 模板,且对安全性要求高的场景,比如从用户输入或第三方 CMS 获取内容时。
2. react-live:交互编辑型
react-live 支持完整的函数、组件和 hooks,尤其适合需要实时编辑预览的场景~
基本用法:
import { LiveProvider, LivePreview } from 'react-live';
<LiveProvider code="() => <div>Hello World</div>" noInline>
<LivePreview />
</LiveProvider>
优势:
- 支持完整函数、组件和 hooks 语法
- 自带动态实时编辑功能(做编辑器超方便)
- 内置 Error 捕获,不怕崩溃
缺点:
- 执行过程有安全风险(需额外注意)
- 通常限于编辑器类场景
- 打包体积会比简单方案大一些
适合场景:
需要动态运行完整 React 代码的场景,如技术博客的代码演示、React 学习平台等。
3. babel-standalone + new Function:高级灵活型
这是最灵活的方案,通过手动 transform
编译再用 new Function
执行,可以实现最大程度的自定义。
基本实现:
import { transform } from '@babel/standalone';
function jsxToElement(jsxString) {
const compiledCode = transform(jsxString, { presets: ['react'] }).code;
const Component = new Function('React', `return (${compiledCode})`)(React);
return React.createElement(Component);
}
// 使用示例
const element = jsxToElement(`() => <div>Hello Dynamic JSX</div>`);
优势:
- 最灵活,几乎没有功能限制!
- 支持各种高级特性(async/await、函数组件、hooks、状态管理等)
- 真正实现"输入 JSX 字符串 → 输出 React 元素"的完整转换
缺点:
- 需要自己处理安全风险(防止恶意代码执行)
- Babel 体积较大(如果整体引入而非按需加载)
适合场景:
需要高度自定义运行环境的场景,如高级 CMS 系统、动态表单渲染器、自建 Playground 等。
安全防护措施
处理字符串转 JSX 最大的风险是执行恶意代码。以下是一些实用的安全措施,建议根据项目需求选择性使用~
基础防护
-
黑名单关键词检查
直接扫描代码中的危险词如window
、document
、eval
等,快速过滤明显的攻击代码。 -
严格模式限制
使用new Function('React', '"use strict"; return (...)')
强制开启严格模式,防止 this 指向全局对象。 -
异常捕获
用 try-catch 包裹所有执行过程,遇到错误立即显示友好提示,避免页面崩溃。try { return jsxToElement(code); } catch (err) { return <div className="error">渲染出错: {err.message}</div>; }
-
返回类型校验
检查返回值是否为合法的 React 元素,防止运行时异常。
高级安全措施
- AST 深度扫描:利用 Babel parser 进行语法树分析,能更精确地识别危险代码模式。
- iframe 沙盒隔离:将动态代码放在隔离环境中执行,即使有问题也不会影响主应用。
选择建议:
- 小型项目,对安全性要求高:选择 react-jsx-parser
- 需要实时编辑预览功能:选择 react-live
- 需要最大灵活性和控制力:选择 babel-standalone + new Function