Reactのstate(prop)内で改行文字を使いたい場合
JSX構文
ReactはJSXを採用しているので、構文の中で以下のようにhtmlタグを直接書くようににコーディングできます。
var Test = React.createClass( { // 処理とか }, render: function() { return( <div> {this.state.foobar} </div> ); } );
しかし、このhtmlタグライクなものは、実際のhtmlタグ(DOMノード)ではなく、React側で用意したコンパイラになります。
この<div>は、React.createElement(div)を呼び出しています。
以上のことより、ReactはHTML文字列を生成していないため、XSS対策の必要がありません。
問題
しかし同時に、HTML文字列を直接生成していないということは自分の意図したタグ(改行とか)を入れられないということになります。
<br>に関しては、<br />を使えば改行できますが、8行目のようなReactが管理している値の中に<br>や"\r\n"のような改行文字があっても、それらは単なるStringとして表されるので改行されることはありません。
ここで改行したい<br>さらにここでも改行したい<br>これが最終行
↑こんな風に無改行で表示されてしまします。
対策
ここで改行したい さらにここでも改行したい これが最終行
こんな風にするには一工夫が必要です。
var Test = React.createClass( { this.setState({foobar: 'ここで改行したい<br>さらにここでも改行したい<br>これが最終行'}); }, render: function() { var lines = this.state.foobar.split('<br>').map(function(line) { return (<p>{line}</p>); }); return( <div> {lines} </div> ); } );
- まずstateに入っている文字列を改行文字(<br>や\r\n)で分割します
- その後に、mapを使ってそれぞれを<p>タグで囲みます
- 実際のreturn内ではlinesを呼び出すだけにします
これで<p>タグによって改行される文字列が完成です。
実際は以下のようになります
<p>ここで改行したい</p> <p>さらにここでも改行したい</p> <p>これが最終行</p>
このままだと行間がすごいあいてしまうので、p タグにクラス属性をつけて、cssを設定してやれば行間もなくなります。
React
. . return (<p className='res-line'>{line}</p>); . .
p.res-line { margin: 0; }
※classNameに関しては以下を参照してください
http://portaltan.hatenablog.com/ReactのJSX構文内でclass属性を設定する場合 - 脳汁portal
この問題は色んな人がひっかかってるようで、調べると日本語でも色んなブログが出てきます。
Reactはこういう細かいところの融通がまだきかない気がするので、今後に期待したいです。
(2015/08/11追記)
ちょっと改良
このままだと一つのstateにしか対応してないので、表示するstate毎に処理を書かなければいけない。
ので改良した。
var Test = React.createClass( { getInitialState() { return { foo: '', bar: '' }; }, . . . render: function() { function lines(line) { if (line) { return (<p className='no-margin'>{line}</p>); } else { return (<p className='no-margin'> </p>); } } return ( <div> {this.state.foo.split('<br>').map(lines)} {this.state.bar.split('<br>').map(lines)} </div> ); }