繁体   English   中英

如何将JSX组件与dangerouslySetInnerHTML结合使用

[英]How to combine JSX component with dangerouslySetInnerHTML

我正在显示存储在数据库中的文本。 数据来自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导入的<Link>组件。但是,因为它是原始HTML,所以dangerouslySetInnerHTML不再正常工作。

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

您可以将文本拆分为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 明显的例外是与第三方库集成,仍应仔细考虑。

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

我以相当粗暴的方式使用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>
    );
  }

}

希望这会有所帮助!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM