React 中 HTML 插入的全场景实践与安全指南

发布于:2025-06-07 ⋅ 阅读:(13) ⋅ 点赞:(0)

在 React 开发过程中,我们常常会遇到需要插入 HTML 内容的场景。比如将服务端返回的富文本渲染到页面,还有处理复杂的 UI 结构,正确的 HTML 插入方式不仅影响页面展示效果,更关乎应用的安全性。

本文将详细探讨 React 中插入 HTML 的多种方式,并结合实际案例分析其使用场景与安全注意事项。

一、使用 JSX 重构(推荐)

适用场景:
当 HTML 内容可控且简单时,优先将 HTML 转换为 JSX。

优点:

  • 类型安全,避免 XSS 攻击
  • 保持 React 的数据绑定和事件处理能力
  • 更好的性能和可维护性

例如,对于以下 HTML 代码:

<div class="title">Hello <b>World</b></div>

我们可以轻松将其转换为 JSX:

const element = (
  <div className="title">
    Hello <b>World</b>
  </div>
);

function App() {
  return <>{element}</>;
}

通过这种方式,React 能够对元素进行高效管理,确保在状态变化时页面的正确更新,同时避免潜在的安全隐患。

二、dangerouslySetInnerHTML:风险与便利并存

适用场景:
当必须插入不可控的 HTML(如用户输入、第三方内容)时。

dangerouslySetInnerHTML 是 React 内置的原生属性,允许我们在组件中直接插入 HTML 字符串。它为我们提供了一种绕过 JSX 直接操作 DOM 的途径,但由于其名称中包含 “dangerously”,也在警示我们该方法存在潜在的安全风险,如 XSS 攻击。

注意事项:

  • 安全风险:永远不要对用户输入使用此属性,可能导致 XSS 攻击
  • 性能开销:每次渲染都会重新解析 HTML
  • 事件丢失:插入的 HTML 中的事件处理会失效

使用 dangerouslySetInnerHTML 的基本语法如下:

function App() {
  const html = '<div class="title">Hello <b>World</b></div>';
  
  return (
    <div
      dangerouslySetInnerHTML={{
        __html: html, // 必须使用 __html 键
      }}
    />
  );
}

在实际应用中,该属性适用于插入来自可信源(如后端 API 返回)的 HTML,或者当内容复杂且难以用 JSX 重构(如富文本编辑器输出)的场景 。但如果直接插入用户输入的内容(如评论、表单数据),则可能导致严重的代码注入问题:

// 危险示例:用户输入未经过滤
const userInput = '<script>alert("XSS")</script>';
<div dangerouslySetInnerHTML={{ __html: userInput }} />; // 直接执行恶意代码

因此,当必须插入用户内容时,我们需要使用 sanitizer 库(如 dompurify)对内容进行过滤:

import DOMPurify from 'dompurify';

const cleanHtml = DOMPurify.sanitize(userInput);
<div dangerouslySetInnerHTML={{ __html: cleanHtml }} />;

三、通过 ref 手动操作 DOM

适用场景:
当需要完全控制 DOM 且不依赖 React 的渲染系统时。

示例代码如下:

function App() {
  const ref = useRef(null);

  useEffect(() => {
    if (ref.current) {
      ref.current.innerHTML = '<div class="title">Hello World</div>';
    }
  }, []);

  return <div ref={ref} />;
}

除非有特殊需求,否则不建议在常规开发中使用这种方式。

注意事项:

  • 违背 React 的声明式理念,可能导致状态不同步
  • 需要手动管理生命周期(如清理)
  • 容易引发性能问题

四、使用第三方库(如 react-html-parser)

适用场景:
在处理复杂 HTML 并希望保持 React 特性时,我们可以借助第三方库,如 react-html-parser。通过安装该库(npm install react-html-parser),我们可以将 HTML 自动转换为 React 元素树,同时保留事件处理能力。

使用方式如下:

import parse from 'react-html-parser';

function App() {
  const html = '<div class="title">Hello <b>World</b></div>';
  return <div>{parse(html)}</div>;
}

这类库在解析富文本内容、处理从其他系统导入的 HTML 数据时非常实用。

优点:

  • 自动转换 HTML 为 React 元素
  • 支持自定义标签处理
  • 保留事件处理能力

五、性能考量

  • dangerouslySetInnerHTML 和手动操作 DOM 会绕过 React 的虚拟 DOM 优化
  • 频繁更新 HTML 内容时,可能导致严重的性能问题
  • 推荐使用 useMemo 缓存解析结果
const parsedHtml = useMemo(() => parse(html), [html]);

六、总结

方法 安全性 适用场景 推荐度
JSX 重构 可控的简单 HTML ⭐⭐⭐⭐⭐
dangerouslySetInnerHTML ⚠️ 不可控的信任 HTML ⭐⭐⭐
手动操作 DOM ⚠️ 完全自定义 DOM 操作 ⭐⭐
react-html-parser 复杂 HTML 解析 ⭐⭐⭐⭐