【问题标题】:How to combine JSX component with dangerouslySetInnerHTML如何将 JSX 组件与 dangerouslySetInnerHTML 结合起来
【发布时间】:2015-11-16 03:56:22
【问题描述】:

我正在显示存储在数据库中的文本。数据来自 firebase 作为字符串(包括换行符)。为了使其显示为 HTML,我最初做了以下操作:

<p className="term-definition"
        dangerouslySetInnerHTML={{__html: (definition.definition) ? definition.definition.replace(/(?:\r\n|\r|\n)/g, '<br />') : ''}}></p>

这很好用。但是,还有一个附加功能。用户可以输入[word],这个词就会链接起来。为了实现这一点,我创建了以下函数:

  parseDefinitionText(text){
    text = text.replace(/(?:\r\n|\r|\n)/g, '<br />');
    text = text.replace(/\[([A-Za-z0-9'\-\s]+)\]/, function(match, word){
      // Convert it to a permalink
      return (<Link to={'/terms/' + this.permalink(word) + '/1'}>{word}</Link>);
    }.bind(this));
    return text;
  },

我省略了 this.permalink 方法,因为它不相关。如您所见,我正在尝试返回从 react-router 导入的 &lt;Link&gt; 组件。但是,由于它是原始 HTML,dangerouslySetInnerHTML 不再正常工作。

所以我有点卡在这一点上。我可以做些什么来格式化内部文本并创建链接?

【问题讨论】:

    标签: javascript reactjs react-router react-router-component


    【解决方案1】:

    您可以将文本拆分为 Links + 字符串数组,如下所示:

    import {Link} from 'react-router';
    
    const paragraphWithLinks = ({markdown}) => {
      const linkRegex = /\[([\w\s-']+)\]/g;
    
      const children = _.chain(
        markdown.split(linkRegex) // get the text between links
      ).zip(
        markdown.match(linkRegex).map( // get the links
          word => <Link to={`/terms/${permalink(word)}/1`}>{word}</Link> // and convert them
        )
      ).flatten().thru( // merge them
        v => v.slice(0, -1) // remove the last element (undefined b/c arrays are different sizes)
      ).value();
    
      return <p className='term-definition'>{children}</p>;
    };
    

    这种方法最好的一点是无需使用dangerouslySetInnerHTML。使用它通常是一个非常糟糕的主意,因为您可能会创建 XSS 漏洞。例如,这可能使黑客能够从您的用户那里窃取登录凭据。

    在大多数情况下,您不需要使用dangerouslySetHTML。明显的例外是与第 3 方库的集成,仍应仔细考虑。

    【讨论】:

    • 什么是_.chain?你在使用下划线吗?我没有把它作为这个项目的一部分,也不想添加额外的依赖项。
    • 来自lodash。非常类似于下划线,非常棒。我已经为您提供了如何创建 Markdown 解析器的要点 - 实现取决于您。
    • _.chain 允许您按顺序执行函数,将输入从一个函数馈送到下一个函数。
    【解决方案2】:

    我遇到了类似的情况,但是接受的解决方案对我来说不是一个可行的选择。

    我以相当粗略的方式与react-dom 合作。我将组件设置为侦听单击事件以及单击是否具有react-router-link 类。发生这种情况时,如果项目设置了data-url 属性,则它使用browserHistory.push。我目前使用的是同构应用,而这些点击事件对服务器生成没有意义,所以我只是有条件地设置这些事件。

    这是我使用的代码:

    import React from 'react';
    import _ from 'lodash';
    import { browserHistory } from 'react-router'
    
    export default class PostBody extends React.Component {
      componentDidMount() {
        if(! global.__SERVER__) {
          this.listener = this.handleClick.bind(this);
          window.addEventListener('click', this.listener);
        }
      }
    
      componentDidUnmount() {
        if(! global.__SERVER__) {
          window.removeEventListener("scroll", this.listener);
        }
      }
    
      handleClick(e) {
        if(_.includes(e.target.classList, "react-router-link")) {
          window.removeEventListener("click", this.listener);
          browserHistory.push(e.target.getAttribute("data-url"));
        }
      }
    
      render() {
        function createMarkup(html) { return {__html: html}; };
    
        return (
          <div className="col-xs-10 col-xs-offset-1 col-md-6 col-md-offset-3 col-lg-8 col-lg-offset-2 post-body">
            <div dangerouslySetInnerHTML={createMarkup(this.props.postBody)} />
          </div>
        );
      }
    
    }
    

    希望对您有所帮助!

    【讨论】:

      猜你喜欢
      • 2019-11-08
      • 2021-10-27
      • 1970-01-01
      • 2020-09-09
      • 1970-01-01
      • 1970-01-01
      • 2018-12-08
      • 2012-03-17
      • 2017-12-15
      相关资源
      最近更新 更多