2

データベースに保存されたテキストを表示しています。データはfirebaseから文字列として取得されます(改行が含まれています)。HTMLとして表示するには、もともと次のことを行いました。

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

これはうまくいきました。ただし、追加機能が 1 つあります。ユーザーが入力[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関係ないので割愛します。<Link>ご覧のとおり、react-router からインポートされたコンポーネントを返そうとしていますが、生の HTML であるため、dangerouslySetInnerHTML適切に動作しなくなりました。

だから私はこの時点でちょっと立ち往生しています。内部テキストの書式設定とリンクの作成の両方を行うにはどうすればよいですか?

4

2 に答える 2

2

次のように、テキストをリンク + 文字列の配列に分割できます。

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。明らかな例外は、サードパーティのライブラリとの統合です。これについても慎重に検討する必要があります。

于 2015-11-16T04:36:53.893 に答える
1

私は同様の状況に遭遇しましたが、受け入れられた解決策は私にとって実行可能な選択肢ではありませんでした.

私はこれを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>
    );
  }

}

これが役立つことを願っています!

于 2016-10-06T19:58:42.907 に答える