[英]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.