本文详解为何 `dangerouslysetinnerhtml` 无法渲染 react 组件(如 `syntaxhighlighter`),并提供基于 `react-html-parser` 的可靠解决方案:通过 `transform` 函数精准拦截 “ 标签,动态注入正确大小写的 jsx 组件,兼顾安全性、可维护性与语法高亮需求。
在 CMS 驱动的博客场景中,你常会接收原始 HTML 字符串(例如 CKEditor 输出的
<code>a = 1 + 2</code>
),并希望将其渲染为带语法高亮的 React 组件。一个常见误区是尝试将 JSX 字符串(如 …)直接拼接进 HTML 字符串,再通过 dangerouslySetInnerHTML 渲染——这必然失败,因为浏览器只解析标准 HTML,而 SyntaxHighlighter 是 React 组件,非 HTML 元素;更关键的是,HTML 解析器会将自定义标签名强制转为小写(syntaxhighlighter),导致 React 无法识别。
✅ 正确路径是:解析 HTML 结构 → 识别语义节点 → 动态替换为真实 React 元素。推荐使用 react-html-parser(v2+)配合其 transform 选项,它在解析过程中逐节点回调,允许你对特定标签(如 )返回完全可控的 JSX:
import React from 'react';
import ReactHtmlParser from 'react-html-parser';
import { SyntaxHighlighter } from 'react-syntax-highlighter';
import { dark } from 'react-syntax-highlighter/dist/cjs/styles/hljs';
function transform(node) {
// 精准匹配 <code> 标签(注意:需同时处理 <pre class="brush:php;toolbar:false;"><code> 嵌套结构)
if (node.type === 'tag' && node.name === 'code') {
// 提取 code 内容(兼容文本节点或嵌套标签)
const codeText = node.children?.find(child => child.type === 'text')?.data || '';
return (
<SyntaxHighlighter
language="python"
style={dark}
customStyle={{ margin: '1rem 0', borderRadius: '6px' }}
>
{codeText.trim()}
</SyntaxHighlighter>
);
}
}
// 在组件中使用
function Post({ htmlContent }) {
return (
<article className="post-content">
{ReactHtmlParser(htmlContent, { transform })}
</article>
);
}
⚠️ 注意事项: