こんにちは、エリカです。
バージョン 5.5 になった「 Laravel 」より、フロントエンドフレームワークに React をカンタンに指定できるようになりました。実際にどんな感じになったのか、ちょっといじってみたいと思います。
▼「 Laravel 」に関する過去記事はこちら 洗練された『Laravel』のメール送信機能を使ってみる 『Laravel』を使ってカンタンなお問い合わせフォームを作ってみた PHPフレームワーク「Laradock」で、手軽にLaravel+Dockerな開発環境を構築する
目次
「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 の中身をいつものようにデータベースと連携し、追加・変更・削除用のエンドポイントを準備すれば、画面とデータ処理のロジックを綺麗に分離できそうですね。
LIGはWebサイト制作を支援しています。ご興味のある方は事業ぺージをぜひご覧ください。