🐕

React+Laravelのルーティング

2021/09/06に公開

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でルーティングを設定します。

routes/web.php
Route::get('/{any}', function () {
    return view('index');
})->where('any', '.*');

/{any}に合致した時に、index.blade.phpがレンダリングされます。
where('any', '.*')anyがすべての文字が0回以上繰り返した文字列つまりすべてのURLでヒットするようになります。

次は、レンダリングされるindex.blade.phpについてです。

resource/views/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ファイルをコンパイルする先を設定します。

webpack.mix.js
mix.js('resources/js/app.js', 'public/js')

上記の記述でresources/js/app.jspublic/js/app.jsとしてコンパイルできるように設定します
下記コマンドでコンパイルを行います。

npm run dev

上記で設定したresources/js/app.js内でcomponents/indexを読み込みます。

resources/js/app.js
require('./components/index');

3.呼び出したjsファイル内で現在のURLでコンポーネントを振り分ける

下記ファイルで現在のURLによってレンダリングされるコンポーネントを振り分けます

resources/js/components/index.js
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>
}

下記を例に説明します。
Routeexactと設定されているのでURLが/usersと完全に一致する時のみ、UsersListコンポーネントを描画します。

<Route exact path="/users" component={UsersList} />

下記の記述でreact-routeruseParamsを使うとルーティングパラメータ:idを使うことができます。その説明はまた別の機会に、、、

<Route exact path="/users/:id" component={UsersShow} />

以上です。読んでいただきありがとうございました。
誤字、間違い等ありましたらコメント頂ければ幸いです。

参考記事

Discussion