React再入門 Part2

従来のRailsでの開発の欠点

Railsでは一つのURLに対して一つのアクションが対応していて例えば/usersにGETリクエストを送るroutes.rbを参照して

resources :users  

みたいな行があると
「あ、今回はUsers Controllerのindexアクションをみに行けばいいんだな」
ってRails側で判断してくれて

def index  
 @users = User.all  
end  

みたいなメソッドがあってapp/views/users/index.html.erbを最終的に返却してくれる。
すごくざっくりした説明だけどRailsを扱ったことがある人なら大部分の人が納得してくれると思う。
けどもしあなたが会社でTwitterやFacebookのようなSNSアプリやSmartNewsやLINENewsといったページ全体を更新せず画面の一部だけがリアルタイムで更新されるアプリケーションの開発を頼まれたらどうしますか?(例えば、の話ですよ!)
あれを従来のフルスタックでのRailsで再現しようとしたらおそらくjQueryゴリ押しの実装になることは間違いない。。。
Rails自体はとても優秀だ。僕も何度もお世話になっているし少人数でのチーム開発でプロトタイプを制作するには素晴らしいFWだと思う。
しかし今回の様に非同期通信をがっつり求められるアプリケーションの開発の場合どうしても単一のURLに対してそれに紐付くリソース及びHTMLファイルをコントローラの処理が終わってから返却する、というシRailsのシステムは分が悪いのかな?って感じがする。
じゃあフルスタックのRails開発をやめてフロントをReactで置き換えれば万事解決じゃん。
。。。って言うのは簡単なんだけどじゃあ実際にどう実装するのって話。

Reactにおける単一データフロー

ReactはVueやAngularが採用しているデータバインディングを採用していない。
常にデータは親コンポーネントから子コンポーネントへ一方向に流れる様になっている。
じゃあ子コンポーネントの変更をどうやって親に渡すのか?って多くの方が疑問に思うのではないだろうか。
結論から言うと親コンポーネントから子コンポーネントに自身のStateを変更する関数を渡してやる、と言うもの。
これがまた大変難しい。サーバサイドだけやっているとこんな実装にお目にかかる機会はそうないからね。
何はともあれコードで示して見よう。

class Board extends React.Component {  
  constructor(props) {  
    super(props);  
    this.state = {  
      squares: Array(9).fill(null)  
    };  
  }  

  handleClick(i) {  
    const squares = this.state.squares.slice();  
    squares[i] = "X";  
    this.setState({ squares: squares });  
  }  

  renderSquare(i) {  
    return (  
      <Square  
        value={this.state.squares[i]}  
        onClick={() => this.handleClick(i)}  
      />  
    );  
  }  

  render() {  
    const status = "Next player: X";  

    return (  
      <div>  
        <div className="status">{status}</div>  
        <div className="board-row">  
          {this.renderSquare(0)}  
          {this.renderSquare(1)}  
          {this.renderSquare(2)}  
        </div>  
        <div className="board-row">  
          {this.renderSquare(3)}  
          {this.renderSquare(4)}  
          {this.renderSquare(5)}  
        </div>  
        <div className="board-row">  
          {this.renderSquare(6)}  
          {this.renderSquare(7)}  
          {this.renderSquare(8)}  
        </div>  
      </div>  
    );  
  }  
}  

これはReact公式チュートリアルから拝借してきたBoardコンポーネントのコード。
この中の

  renderSquare(i) {  
    return (  
      <Square  
        value={this.state.squares[i]}  
        onClick={() => this.handleClick(i)}  
      />  
    );  
  }  

ここに注目して欲しい。
SquareコンポーネントにonClick Propsとして自身のsquare Stateを更新するhandleClick関数を渡している。

  handleClick(i) {  
    const squares = this.state.squares.slice();  
    squares[i] = "X";  
    this.setState({ squares: squares });  
  }  

handleClick関数の処理は簡単でsquares定数に現在のsquares State配列の要素をスライスして代入してi番目の要素を文字列Xで更新するというもの。
Squareコンポーネントの中身はこんな感じ。

class Square extends React.Component {  
  render() {  
    return (  
      <button className="square" onClick={() => this.props.onClick()}>  
        {this.props.value}  
      </button>  
    );  
  }  
}  

onClickイベントには親要素、つまりBoardコンポーネントから渡されたonClick Propsを代入していてクリックするとSquareコンポーネントを通してhandleClick関数が発火してsquares Stateが更新されるという仕組み(で合ってるかな?)。
多分実感するには自分でReactの公式チュートリアルをローカルで試してみるのがてっとり早いと思う。。。

最後に

最近Reactに再入門したばかりの身なので間違いっている箇所などございましたらコメント欄で優しく指摘して頂けると幸いです。。。。