React+Laravelのルーティング
LaravelとReactでSPA(single-page application)の疑似的にルーティングを実装する方法を説明します。
SPAを作るので、呼び出すページは基本的に1つです。呼び出したページの中でreact-router-domを使ってURLによってコンポーネントに振り分けていきます。
上記をまとめると動きは下記のようなになっています。
1.Laraveのルーティングで1つのページをレンダリングする。
2.呼び出したページで呼び出されるjsファイルにコンパイル先を設定する。
3.呼び出したjsファイル内で現在のURLでコンポーネントを振り分ける。
1.Laraveのルーティングで1つのページをレンダリングする。
どのURLにアクセスしても1つのページindex.blade.phpがレンダリングされるようにweb.phpでルーティングを設定します。
Route::get('/{any}', function () {
return view('index');
})->where('any', '.*');
/{any}に合致した時に、index.blade.phpがレンダリングされます。
where('any', '.*')でanyがすべての文字が0回以上繰り返した文字列つまりすべてのURLでヒットするようになります。
次は、レンダリングされるindex.blade.phpについてです。
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>Laravel</title>
<script src="{{ asset(mix('js/app.js')) }}" defer></script>
</head>
<body>
<div id="index"></div>
</body>
</html>
下記の行でコンパイルされたapp.jsが読み込まれます。
app.jsが「3.呼び出したjsファイル内で現在のURLでコンポーネントを出しわけする。」で実装するjsファイルがコンパイルされるようになります。
<script src="{{ asset(mix('js/app.js')) }}" defer></script>
2.jsファイルをコンパイル先を呼び出されるファイルに設定する。
実装するjsファイルをコンパイルする先を設定します。
mix.js('resources/js/app.js', 'public/js')
上記の記述でresources/js/app.jsをpublic/js/app.jsとしてコンパイルできるように設定します
下記コマンドでコンパイルを行います。
npm run dev
上記で設定したresources/js/app.js内でcomponents/indexを読み込みます。
require('./components/index');
3.呼び出したjsファイル内で現在のURLでコンポーネントを振り分ける
下記ファイルで現在のURLによってレンダリングされるコンポーネントを振り分けます
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route } from 'react-router-dom';
const Index = () => {
<BrowserRouter>
<Route exact path="/users" component={UsersList} />
<Route exact path="/users/:id" component={UsersShow} />
<Route exact path="/users/create" component={UsersCreate} />
<Route exact path="/users/:id/edit" component={UsersEdit} />
</BrowserRouter>
}
if (document.getElementById('index')) {
ReactDOM.render(<Index />, document.getElementById('index'));
}
下記の記述でid='index'の要素があれば、Indexコンポーネントを描画します。
if (document.getElementById('index')) {
ReactDOM.render(<Index />, document.getElementById('index'));
}
下記がIndexコンポーネントの定義です。
それぞれのコンポーネントの役割は下記になります。
-
BrowserRouter:window.location(≒URL)が変わる度にどのRouteに振り分ければいいのかを判断します。 - Route:
location.pathName(≒URL)がpathに一致した時にcomponentが描画する- exact:location.pathNameが完全一致した時のみヒットするようになります
const Index = () => {
<BrowserRouter>
<Route exact path="/users" component={UsersList} />
<Route exact path="/users/:id" component={UsersShow} />
<Route exact path="/users/create" component={UsersCreate} />
<Route exact path="/users/:id/edit" component={UsersEdit} />
</BrowserRouter>
}
下記を例に説明します。
Routeはexactと設定されているのでURLが/usersと完全に一致する時のみ、UsersListコンポーネントを描画します。
<Route exact path="/users" component={UsersList} />
下記の記述でreact-routerのuseParamsを使うとルーティングパラメータ:idを使うことができます。その説明はまた別の機会に、、、
<Route exact path="/users/:id" component={UsersShow} />
以上です。読んでいただきありがとうございました。
誤字、間違い等ありましたらコメント頂ければ幸いです。
参考記事
Discussion