今天服务端的同学想通过后端返回的字符串,通过 br 标签换行处理,但是发现了在前端并不能如愿的换行,这是为什么呢?我们是基于React库来开发前端页面的。

问题解决原因

其实用JS操作原生DOM场景下,我们可以使用 textContent innerHTML 两个API为我们的HTML元素添加内容, textContent 可以直接将文本内容添加到元素中, innerHTML 则会将文本内容解析,再添加到内容中。 我们来看下这段代码执行的结果。

    document.getElementById("p1").innerHTML = "123</br>123"
    document.getElementById("p2").textContent = "123</br>123"
从图中我们不难发现使用innerHTML的元素换行了。

React是怎么生成的文本内容

通常,我们在React中使用的文本内容都会使用textContent生成文本 在React源码中我们可以找到如下代码

  var setTextContent = function (node, text) {
    if (text) {
      var firstChild = node.firstChild;
      if (firstChild && firstChild === node.lastChild && firstChild.nodeType === TEXT_NODE) {
        firstChild.nodeValue = text;
        return;
    node.textContent = text;
 var DANGEROUSLY_SET_INNER_HTML = 'dangerouslySetInnerHTML';
if (propKey === STYLE) {
  setValueForStyles(domElement, propValue);
} else if (propKey === DANGEROUSLY_SET_INNER_HTML) {
  // 当含有DANGEROUSLY_SET_INNER_HTML时候使用innerHTML
  setInnerHTML(domElement, propValue);
} else if (propKey === CHILDREN) {
  setTextContent(domElement, propValue);
} else {
  setValueForProperty(domElement, propKey, propValue, isCustomComponentTag);
// 当children存在且为字符串或者数字时候,设置文本
if (propKey === CHILDREN) {
  if (typeof nextProp === "string") {
    var canSetTextContent = tag !== "textarea" || nextProp !== "";
    if (canSetTextContent) {
      setTextContent(domElement, nextProp);
  } else if (typeof nextProp === "number") {
    setTextContent(domElement, "" + nextProp);

如果我们需要在使用html文本元素怎么办呢?这时候我们的主角登场了。

dangerouslySetInnerHTML

我们在React官方文档中可以找到如下描述 dangerouslySetInnerHTML 是 React 为浏览器 DOM 提供 innerHTML 的替换方案。通常来讲,使用代码直接设置 HTML 存在风险,因为很容易无意中使用户暴露于跨站脚本(XSS)的攻击。因此,你可以直接在 React 中设置 HTML,但当你想设置 dangerouslySetInnerHTML 时,需要向其传递包含 key 为 __html 的对象,以此来警示你。

在React中我们可以看到如下的代码

if (props.dangerouslySetInnerHTML != null) {
  // 当children和dangerouslySetInnerHTML同时存在时候抛错
  if (!(props.children == null)) {
    throw Error(
      "Can only set one of `children` or `props.dangerouslySetInnerHTML`."
var setInnerHTML = createMicrosoftUnsafeLocalFunction(function (node, html) {
  if (node.namespaceURI === Namespaces.svg) {
    if (!("innerHTML" in node)) {
      // IE does not have innerHTML for SVG nodes, so instead we inject the
      // new markup in a temp node and then move the child nodes across into
      // the target node
      // 处理IE边界情况 IE SVG没有innerHTML
      reusableSVGContainer =
        reusableSVGContainer || document.createElement("div");
      reusableSVGContainer.innerHTML =
        "<svg>" + html.valueOf().toString() + "</svg>";
      var svgNode = reusableSVGContainer.firstChild;
      while (node.firstChild) {
        node.removeChild(node.firstChild);
      while (svgNode.firstChild) {
        node.appendChild(svgNode.firstChild);
      return;
  // 设置在这里
  node.innerHTML = html;

强调该方式存在风险,慎用。容易造成跨站脚本(XSS)攻击,如下面这段代码

const App = () => {
  return <div dangerouslySetInnerHTML={{ __html: `<script>console.log('danger')</script>` }}></div>;
ReactDOM.render(<App />, document.getElementById("root"));

我们在控制台中可以看到这段script代码被打印了

image.png

  • 在 React Router 中使用 JWT
  • 基于 ChatGPT 和 React 搭建 JSON 转 TS 的 Web 应用
  • React CSS-In-JS 方案 :  Linaria Vs Styled-Components
  •