Javascript 如何将JSX组件与危险的HTML结合起来

Javascript 如何将JSX组件与危险的HTML结合起来,javascript,reactjs,react-router,react-router-component,Javascript,Reactjs,React Router,React Router Component,我正在显示存储在数据库中的文本。数据以字符串形式来自firebase(包括换行符)。为了使其显示为HTML,我最初执行了以下操作: <p className="term-definition" dangerouslySetInnerHTML={{__html: (definition.definition) ? definition.definition.replace(/(?:\r\n|\r|\n)/g, '<br />') : ''}}></p&

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

<p className="term-definition"
        dangerouslySetInnerHTML={{__html: (definition.definition) ? definition.definition.replace(/(?:\r\n|\r|\n)/g, '<br />') : ''}}></p>
我省略了
this.permalink
方法,因为它不相关。如您所见,我试图返回从react-router导入的
组件。但是,由于它是原始HTML,
危险的HTML
不再正常工作


所以我有点被困在这一点上。如何设置内部文本的格式并创建链接?

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

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>;
};
从'react router'导入{Link};
常量段落WithLinks=({markdown})=>{
常量linkRegex=/\[([\w\s-']+)\]/g;
const children=uz.chain(
markdown.split(linkRegex)//获取链接之间的文本
)zip先生(
markdown.match(linkRegex).map(//获取链接
word=>{word}//并将其转换为
)
).flant().thru(//合并它们
v=>v.slice(0,-1)//删除最后一个元素(未定义的b/c数组大小不同)
).value();
返回

{children}

; };
这种方法最好的地方就是不再需要使用
危险的HTML
。使用它通常是一个非常糟糕的想法,因为您可能会创建XSS漏洞。例如,这可能会使黑客窃取用户的登录凭据


在大多数情况下,您不需要使用
危险的ethtml
。明显的例外是与第三方库的集成,这仍然需要仔细考虑。

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

我使用
react-dom
以一种相当粗糙的方式实现了这一点。我将组件设置为侦听单击事件,如果单击具有
react router link
类。发生这种情况时,如果项目具有
数据url
属性集,则它将使用
浏览器历史记录。推送
。我目前正在使用一个同构的应用程序,这些点击事件对于服务器的生成没有意义,所以我只是有条件地设置这些事件

以下是我使用的代码:

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>
    );
  }

}
从“React”导入React;
从“lodash”进口;
从“react router”导入{browserHistory}
导出默认类PostBody扩展React.Component{
componentDidMount(){
如果(!全局.\uuuu服务器\uuu){
this.listener=this.handleClick.bind(this);
window.addEventListener('click',this.listener);
}
}
componentDidUnmount(){
如果(!全局.\uuuu服务器\uuu){
removeEventListener(“滚动”,this.listener);
}
}
handleClick(e){
如果(u.includes(例如target.classList,“反应路由器链接”)){
window.removeEventListener(“单击”,this.listener);
browserHistory.push(例如target.getAttribute(“数据url”);
}
}
render(){
函数createMarkup(html){return{{uuuuhtml:html};};
返回(
);
}
}

希望这有帮助

什么是链子?你在用下划线吗?我没有把它作为这个项目的一部分,也不想添加其他依赖项。它来自
lodash
。非常类似于下划线,非常棒。我已经向您介绍了如何创建标记解析器的要点—具体实现取决于您。
.chain
允许您按顺序执行函数,将输入从一个函数传递到下一个函数。
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>
    );
  }

}