簡體   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