React移行メモ

  • 37
    いいね
  • 0
    コメント

Rails4アプリのjQueryフロントエンドをReact.jsに置き換えるリファクタ活動を始めたので、これまでの理解をメモ

コードの臭い

  • (jQueryによる)DOM操作・クラス操作の累積
  • addしてremoveしてaddしてhide...本当に意図通り動いているのか、何か忘れてないか
  • 特殊なDOM構成の存在を前提とした操作
  • DOMがどこから操作されているのか不明

移行指針

  • 問題の変換
    • 状態変化に伴うDOM操作の処理を自分で計算せず、すべてrenderに押し付ける
    • HTML差分計算・再描画に関する問題・思考を最小化し、stateの操作に集中することでビジネスロジックの整合性を確認する
  • 双方向の思考を一応念頭に置く
    • ボトムアップ、コンポーネント指向(?)
      • 小さいコンポーネントを先に置き換えて、大きいコンポーネントでそれを使う
    • トップダウン、インターフェース指向(?)
      • 大きいコンポーネントを先に置き換えて、途中で出てきた再利用性の高い部分をどんどん別コンポーネントに分割する
  • ついでにいろいろできそうだが、最小の工数で移行する

入り口

  • どこから導入すべきか
  • 修正の必要が発生したが、DOM操作がすでに溢れ、次の修正でバグが入りそうな箇所
    • DOM操作を追加・修正せざるを得ない箇所
    • API経由の遅延描画に置き換えたい箇所
  • 壊れていないものを直そうとしない
    • もし静的解析で定量化できたら、複雑な箇所から置き換える

準備

コンポーネント作成

以下、React.ComponentベースでなくReact.createClassでコンポーネントを作る前提。

  • 置き換えたいDOM構造の現状を把握する

    • せっかくリファクタするのであれば必要十分な数のDOMになるのが理想
    • ここではとりあえず置き換えるのをゴールとして、既存のHTMLのコピペでJSXを構成する
  • コンポーネント作る

    • rails g react:component
    • テンプレートで既にpartial使っているなら、感覚としては似ている。淡々とpartial単位でおきかえていくイメージ
  • 一思いにブラウザでouter htmlをコピー、beautify https://ctrlq.org/beautifier/ とか

  • renderにhtmlをペーストする

  • classとなっているところをclassNameにもれなく置き換える

  • HTML内にstyleが記述されているところはひとまずinner styleに置き換える

  • 一応、もとのslimなどと見比べて自分を納得させる

コンポーネント修正

  • componentDidMountgetInitialStateなどだいたい必要になるので書く
  • レンダリング内容取得のAPIが必要になればそれも書く
  • スクロール位置などのDOM属性を参照したくなったらrefを使う
  • 必要に応じてJSのcallbackやclosureなどをうまく使って構造化する

ハマりどころ

  • 出現する条件がレアなDOMを見落として移行から漏れる
    • これを防ぐのがReact化の目的の一つだが、できればこのタイミングでもなんとかしたい
  • setStateは即座にstateを変更してくれるわけではない
    • 直前のsetStateでstateが変更された前提でstateへの参照をしているとハマる
    • this.stateを参照する処理は最小限にするか、renderに押し込む?
  • 何も考えずにReactコンポーネントとしてラップするとDOM階層が一つ増える
    • 子セレクタに依存するスタイル命名規則をつかっているとCSS/JSの挙動が変わる
    • たとえば、RSCSSを使わない
      • もしくは階層に関する命名制約を外す
  • mapなどで同じ要素を複数並べるときはkeyで一意性を保つようにする
    • 一意性が保たれていない場合、二つ目以降の要素が描画されない
  • render内でreturnしたくなったときはreturn nullする

効果

  • 人力DOM操作によるバグが減る
  • データ取得の処理がコンポーネント自身にカプセル化される
    • アプリのどこでコンポーネントを呼び出してもだいたい正しく動く
  • 共起するあらゆるDOMを同一コンポーネントのJSXでほぼ説明できる

宿題

  • 荒療治でも案外素直に動くので、やり残していることがいっぱい
  • 無駄なバリデーション
    • prop typesを使いたい人生
  • mixin
    • たとえばrenderだけがちがう複数のコンポーネントをどう綺麗に実装すべきか
    • overrideしたい
    • デザインパターンをうまく使いたい
  • redux
    • スタンダードになりつつあるようだが理解が追いついていないので保留
    • どのような問題が解決されるのか
    • どのような依存が発生するのか
  • テスティング?
  • React.createClassからReact.Componentベースへの書き換え

葛藤

  • DOM操作の複雑さがstate操作の複雑さへ保留される
    • とはいえ、単なるデータ構造の問題へ縮小している
  • DOM構造やinline styleをJS内に書くことになる
    • 今まで守ってきたHTML/CSS/JSの分離とはなんだったのか
  • サーバー > クライアント、クライアント > サーバのデータの流れが同じところで行われ、依然見通しが悪い
  • comfort zoneからの巣立ち
    • CoffeeScriptで書きたかった
    • Slimで書きたかった

解決済の問題が多そう・Reactの恩恵を100%受けていなさそうなので、引き続き勉強する