Aqutras Members' Blog

株式会社アキュトラスのメンバーが、技術情報などを楽しく書いています。

Reactでセル内で自動改行と文字コードによる改行を両立させる方法

こんにちは、joniyです。
もうすぐ春アニメも終わってしまいますね。
今期で乗りに乗っていて常におもしろかったのは「この素晴らしい世界に祝福を!」でしょうか。
2期も決定してもう言うこと無いですね。ありがとうございます!!!!!!

はい、本題に入ります。

問題

2016/03/16ぐらいから、Reactをフロントで使っているプロジェクトで
セルから文字がはみ出るようになりました。

元々の実装(一部)

   |  ...
 1 |    var innerValue = this.props.value;
 2 |    if this.props.multiLine
 3 |      innerValue = <pre>{innerValue}</pre>
 4 |  render() {
 5 |    <td>{innerValue}</td>
 6 |  }
   |  ...

このようにpreタグを付けることでセル内で改行コードによる改行を実装していました。
これでも、問題なく意図した表示がされていたと思うのですが、
ブラウザ(Chrome)のpreタグの優先度が上がったのかもしれません。

表示結果
f:id:joniy_joniy:20160325195711p:plain

結論

改行コード毎に別コンポーネントを呼び出して、
呼び出し先コンポーネントで末尾に<br />を付けることで解決しました。

呼び出し元コンポーネントの一部

   |  ...
 1 |    var multiLineCells = [];
 2 |    var splitValues = innerValue.split('\n');
 3 |    for (index in splitValues) {
 4 |      eachLine = splitValues[index];
 5 |      multiLineCells.push(<MultiLineCell key={key} eachValue={eachLine} />);
 6 |    innerValue = multiLineCells;
 7 |  render() {
 8 |    <td>{innerValue}</td>
 9 |  }
   |  ...

呼び出し先コンポーネント

   1 |class MultiLineCell extends React.Component {
   2 |  constructor(props) {
   3 |    super(props);
   4 |  }
   5 |
   6 |  render() {
   7 |    return (
   8 |      <div>{this.props.eachValue}<br /></div>
   9 |    );
  10 |  }
  11 |}
  12 |
  13 |MultiLineCell.PropTypes = {
  14 |  eachValue: React.PropTypes.string.isRequired
  15 |};
  16 |window.MultiLineCell = MultiLineCell

解決策の模索経緯

preタグを消してみる

単純にpreタグを消してみました。
改行コードで改行してくれなくなりました。まあそうですよね(´・ω・`)

表示結果
f:id:joniy_joniy:20160325195838p:plain

CSSで指定してみる

word-wrapwhite-spaceword-breakを試してみましたが、
どれもセル内で自動改行と文字コードによる改行を両立できませんでした。

\nを<br>に置き換えてみる

brタグをhtmlタグと認識してくれなかったのでアウト。

表示結果
f:id:joniy_joniy:20160325202700p:plain

改行コード毎に別コンポーネントを呼び出す

最終的にこの方法で解決しました。

表示結果
f:id:joniy_joniy:20160325200019p:plain

終わりに

ちょっとゴリ押しで解決してしまったのでは?と思いますが、
元コードの変更箇所も少ないので悪くない解決方法だと思います。

新しいコンポーネントを作成するついでにES6で書いてみました。
最近ずっとCoffeeScriptに慣れていたのでセミコロンが新鮮でした。

ちなみに、CoffeeScriptとES6をこのReactプロジェクトでは共存させています。
方法はいるかさんさんが記事にまとめてくれているので興味のある方はご参照ください!

RailsでCoffeeScriptを共存させつつES6やJSXを使う方法

オチ

いるかさんさん:今、適当なページでテーブルタグで再現させて、CSSだけで解決できたよー
いるかさんさん:white-space: pre-wrap したら折り返された。
joniy:えっ....

確認してみた。

   |  ...
 1 |    var innerValue = this.props.value;
 2 |    var style = [];
 3 |    if this.props.multiLine
 4 |      style['white-space'] = 'pre-wrap'
 5 |  render() {
 6 |    <td style={style}>{innerValue}</td>
 7 |  }
   |  ...

表示結果
f:id:joniy_joniy:20160325210947p:plain

...。
CSS調べたつもりでしたが確認不足でした...。


最後に一言。
この素晴らしい世界にpre-wrapを!!!!!