k01ken’s b10g

He110 W0r1d!

CakePHP3でReactを利用する

開発環境は、Windows 10 Pro(64bit) + CakePHP 3.7.8。

qiita.com
ここの記事を参考にして、CakePHPのルートディレクトリにて、
必要なモジュールをインストールしたが、bundle.jsを作成する段階でエラーが発生した。そこで、エラーメッセージに書いてある通りに修正すると、何とか動作した。(babelify@8をインストールした後に、babel-coreをインストールすると、うまく動作した。)


・PagesController.php内に、root(),a(),b()アクションをそれぞれ作る。

・/src/Template/Pages内に、a.ctp,b.ctp,root.ctpを作成する。

・/config/routes.phpを開き、Router::scope('/',~の中に追加する。
$routes->connect('/'~の部分は、actionをrootに書き換える。
routes.php

<?php
    $routes->connect('/', ['controller' => 'Pages', 'action' => 'root']);

    $routes->connect('/a', ['controller' => 'Pages', 'action' => 'a']);

    $routes->connect('/b', ['controller' => 'Pages', 'action' => 'b']);
?>

・エントリーポイントになるjavascriptファイルを作成して、以下のコードを書く。
entry.js

import React from 'react';
import {render} from 'react-dom';
import {BrowserRouter, Link, Route} from 'react-router-dom';

function root(){
  return <h1>root</h1>;
}

function a(){
  return <h1>a</h1>;
}

function b(){
  return <h1>b</h1>;
}

class Main extends React.Component{
  render(){
          return(
           <div>
           <BrowserRouter>
          <ul>
            <li><Link to="/">root</Link></li>
            <li><Link to="/a">a</Link></li>
            <li><Link to="/b">b</Link></li>
          </ul>
          <Route exact path="/" component={root} />
          <Route path="/a" component={a} />
          <Route path="/b" component={b} />
        </BrowserRouter>
        </div>
        );
  }
}

render(<Main />, document.getElementById("root"));

default.ctp

<body>
<div id="root"></div>
<script type="text/javascript" src="/js/bundle.js?_=<?= time() ?>"></script>
</body>

・これによって初回アクセス時は普通にhttpでアクセスし、後からは、リンクをクリックすると、ページ遷移をすることなく、動的に、URLを変化させながら、コンテンツの中身も変わる。

コントローラ側からJSON形式で取得する

entry.js

import React from 'react';
import {render} from 'react-dom';
import {BrowserRouter, Link, Route} from 'react-router-dom';

class Main extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      result: ''
    }
  }

  componentDidMount(){
    let url = location.pathname;
    this.readPage(url);
  }

  readPage(url){
    let this_ = this;
     fetch(url,{
      method: 'GET',
      headers: new Headers({ 'Accept': 'application/json', 'X-Requested-With': 'XMLHttpRequest'})
    }).then( function(res){
      return res.json();
    }).then( function(data){
      let test = data.result.message;
      this_.setState({result: test});
    }); 
  }

  render(){
     return(
       <div>
         <BrowserRouter>
           <ul>
            <li><Link to="/" onClick={() => (this.readPage("/"))}>root</Link></li>
            <li><Link to="/a" onClick={() => (this.readPage("/a")}>a</Link></li>
            <li><Link to="/b" onClick={() => (this.readPage("/b")}>b</Link></li>
          </ul>
          <Route exact path="/" render={() => (<h1>{this.state.result}</h1>)} />
          <Route path="/a" render={() => (<h1>{this.state.result}</h1>)} />
          <Route path="/b" render={() => (<h1>{this.state.result}</h1>)} />
        </BrowserRouter>
      </div>
    );
  }
}

render(<Main />, document.getElementById("root"));

コンポーネント内でcomponentDidMountメソッドを利用することで、指定のURLにアクセスした段階で、現在のURLのデータを読み込ませて、表示させています。これをしないと、リンクをクリックしない限り、データを読み込もうとはしません。
ja.reactjs.org


PagesController.php

<?php
  public function initialize(){
    parent::initialize();
  }

  public function root(){
    if($this->request->is(["ajax","get"])){
      $data = ["message" => "root page"];
      $this->set(['result' => $data, '_serialize' => ['result']]);
      return;
    }
  }

  public function a(){
    if($this->request->is(["ajax","get"])){
      $data = ["message" => "a page"];
      $this->set(['result' => $data, '_serialize' => ['result']]);
      return;
    }
  }

  public function b(){
    if($this->request->is(["ajax","get"])){
      $data = ["message" => "b page"];
      $this->set(['result' => $data, '_serialize' => ['result']]);
      return;
    }
  }
?>


参考リンク
React Router v4 でルーティング先の component に Props を渡す方法 - ngzmのブログ
【ajaxを卒業したい】rails+jqueryをreactで書き換えてみた #1 - Qiita
React.jsのComponent Lifecycle - Qiita