PHPフレームワーク「Laravel」を使ってReactデビューしてみよう!

エリカ


PHPフレームワーク「Laravel」を使ってReactデビューしてみよう!

こんにちは、エリカです。

バージョン 5.5 になった「 Laravel 」より、フロントエンドフレームワークに React をカンタンに指定できるようになりました。実際にどんな感じになったのか、ちょっといじってみたいと思います。

▼「 Laravel 」に関する過去記事はこちら

▼目次

「Laravel」でReactデビューしてみよう!

Laravel + Reactのセットアップ

Laradock などで「 Laravel 」をセットアップしてください。 ブラウザで http://localhost にアクセスすると、Laravelの初期画面が出るようになっている状態から始めます。

この状態では、Bootstrap + Vue.js が利用できるようにセットアップされています。

これを React に変更します。

( workspace コンテナ内)

$ php artisan react
React scaffolding installed successfully.
Please run "npm install && npm run dev" to compile your fresh scaffolding.

自前でセットアップしたい場合は、下記のコマンドでフレームワーク用のファイルを削除できます。

( workspace コンテナ内で)

$ php artisan preset none
Frontend scaffolding removed successfully.

試しに実行してみたところ、下記ファイルが変更・削除されました。

modified:   package.json
deleted:    public/css/app.css
deleted:    public/js/app.js
modified:   resources/assets/js/app.js
deleted:    resources/assets/js/components/Example.vue
deleted:    resources/assets/sass/_variables.scss
modified:   resources/assets/sass/app.scss

Reactを使うための準備

ホストマシンの方で laravel のファイルが設置されたディレクトリに移動します。package.json が置かれているディレクトリです。

そこで下記を実行し、React を動かすのに必要なファイルを準備します。

$ npm install && npm run dev

/resources/assets/js/components/Example.js が React のスキャッフォルドです。これがコンパイルされるかと思いますので、とりあえず表示してみましょう。

/resources/views/welcome.blade.php を開き、body の中身を以下のように編集します。

    <body>
        <div id="example"></div>
        <script src="{{mix('js/app.js')}}" ></script>
    </body>

ここでは id 属性が「 example 」というタグを用意しておくと、react-dom により Example クラスの render メソッドの結果が適用されます。

ブラウザで、http://localhost にアクセスして確認しましょう。

Example Component
I'm an example component!

上記のように表示されていれば成功です。

ただ、この状態だとコンソール上で次のようなエラーが出ているかと思います。

CSRF token not found

Laravel 側で Token を要求するしないに関わらず、CSRF Token をセットしておく必要があるみたいです。

その場合は、welcome.blade.php の内に下記を追加しておきましょう。

<meta name="csrf-token" content="{{ csrf_token() }}">

Reactを動かしてみる

それでは、React をいじってみます。ここではリアルタイムで反映されるように、npm run watch を実行し、この状態で先ほどの Example.js の中身を記述していきます。

React では、State という機能を使って状態を管理することができます。

試しに、下記のメソッドを追加します。これは、インスタンス生成時に state のデータをセットしています。

constructor() {
    super();

    this.state = {
            foo: "bar"
    };
}

そして、この state に格納されているデータを画面に表示するようにします。

render() の中身を変更します。

render() {
        return (
            <div className="container">
                <div className="row">
                    <div className="col-md-8 col-md-offset-2">
                        <div className="panel panel-default">
                            <div className="panel-heading">Example Component</div>

                            <div className="panel-body">
                                I'm an example component!
                                <p>{this.state.foo}</p>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        );
    }

先ほどの画面上の {this.state.foo} と記述した部分に” bar “が新たに追加して表示されました。

そして、この State を変更していくと、それが自動的に画面上にも反映されていきます。

試してみます。

componentDidMount というメソッドを追加します。これは render() の後で React により自動的に実行されメソッドです。

componentDidMount() {
        let self = this;
        setInterval(function(){
                var d = new Date;
                self.setState({foo:d.getSeconds().toString()});
        }, 500);
    }

中身は単純で、定期的に現在の秒数で state の中身を上書きしていくものです。ちなみに state の中身を置き換えるときは、setState() を使う必要があります。

画面を見てみましょう。更新しているのは state の中身だけなのですが、その変更に合わせて再描画され、画面上に秒数が表示されていきます。

次は、state に格納するデータを Laravel から API 経由で取得してみたいと思います。

これができれば「 Laravel で API を」、「 React で UI を」ということがカンタンにできそうですね。

APIを準備する

routes/api.php を編集します。

Route::get( '/foo', function ( Request $request ) {

    $pitchers = collect([
        [
            'key'  => 'saito',
            'name' => '斎藤',
            'era'  => 1.62,
            'win'  => 20,
        ],
        [
            'key'  => 'makihara',
            'name' => '槇原',
            'era'  => 2.29,
            'win'  => 12,
        ],
        [
            'key'  => 'kuwata',
            'name' => '桑田',
            'era'  => 2.60,
            'win'  => 17,
        ],
    ]);

    return response()->json( $pitchers );
} );

適当な配列を JSON で出力する簡単なものです。

APIへリクエストして、結果をStateに格納する

Example.js を編集します。


import React, { Component } from 'react';
import ReactDOM from 'react-dom';

export default class Example extends Component {

    constructor() {
        super();

        this.state = {
            pitchers: []
        };

    }

    componentDidMount() {
        fetch('/api/foo')
        .then(response => {
            return response.json();
        })
        .then(objects => {
            this.setState({pitchers:objects});
        });
    }

    renderPitchers() 
    {
        return this.state.pitchers.map(pitcher => {
            return (
            <li key={pitcher.key}>
                名前 : {pitcher.name}<br/>
                勝利数 : {pitcher.win}<br/>
                防御率 : {pitcher.era}<br/>
            </li>      
            );
        });
    }

    render() {
        return (
            <div className="container">
                <div className="row">
                    <div className="col-md-8 col-md-offset-2">
                        <div className="panel panel-default">
                            <div className="panel-heading">Example Component</div>

                            <div className="panel-body">
                                <ul>
                                {this.renderPitchers()}
                                </ul>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
}

if (document.getElementById('example')) {
    ReactDOM.render(<Example />, document.getElementById('example'));
}

constructor() で、state に格納するものを配列に変更しています。


this.state = {
    pitchers: []
};

render() では、renderPitchers() というメソッドを実行するようにします。


<ul>
    {this.renderPitchers()}
</ul>

renderPitchers() 
    {
        return this.state.pitchers.map(pitcher => {
            return (
            <li key={pitcher.key}>
                名前 : {pitcher.name}<br/>
                勝利数 : {pitcher.win}<br/>
                防御率 : {pitcher.era}<br/>
            </li>      
            );
        });
    }

renderPitchers() は、state の配列をループして表示するようになっています。ただ、起動時は対象の配列は空なので、もちろん何もしません。

componentDidMount() {
        fetch('/api/foo')
        .then(response => {
            return response.json();
        })
        .then(objects => {
            this.setState({pitchers:objects});
        });
    }

そして、render() 後に実行される componentDidMount() メソッドで、API へのリクエストを行っています。

前述の、routes/api.php に定義した /api/foo にリクエストを送信し、レスポンスを State にセットしています。

ブラウザで、http://localhost にアクセスすると、API で返すようにした配列が、リストで表示されます。

まとめ

いかがでしたか。API の中身をいつものようにデータベースと連携し、追加・変更・削除用のエンドポイントを準備すれば、画面とデータ処理のロジックを綺麗に分離できそうですね。

 

エリカ
この記事を書いた人
エリカ

ディレクター

おすすめ記事

Recommended by