【3日目】React初学者が1週間でどこまで出来るか挑戦(Inertiaの理解)
はじめに
React学習1週間チャレンジ3日目です。初日はBreezeパッケージのインストールで環境構築しましたが、迷走して再度InertiaとReactをマニュアルでインストールして構築しました。Inertiaについて理解が少し深まりました。
前回の振り返り:
-
【2日目】React初学者が1週間でどこまで出来るか挑戦
- コンポーネントのImportとExport
- JSXのマークアップ
- JSXの構文ルール
- コンポーネントにpropsを渡す
- 条件付きレンダリング
- リストをレンダリングするときの注意
- コンポーネントをpureに保つ
- イベントハンドリングの基礎
- Stateの基礎の基礎
学習ログ
最初に、Breezeパッケージで生成されたjsx
ファイルを見て昨日までドキュメントで学んだ知識でどこまでコードが読めるか確認してみた。
Breezeファイル構成:
-
resources/
-
js/
-
Components/
-
Layouts/
-
Pages/
-
Auth/
-
Profile/
-
Dashboard.jsx
-
Welcome.jsx
-
-
app.jsx
-
-
まず、アプリ/
にアクセスした時に表示されるWelcome.jsx
を確認してみる。
@inertiajs/react
からLink
とHead
をインポートしている。
import { Link, Head } from '@inertiajs/react';
node_modules/@inertiajs/react
を確認。配下に直接Link
やHead
が見当たらないがpakage.json
によってロードするべき主要なエントリーポイントを指定され適したファイルがロードされているみたい。
次に、Welcome
メソッドがデフォルトエクスポートされている。propsが指定されている。
export default function Welcome({ auth, laravelVersion, phpVersion }) {
// ...省略
}
呼び出し元を確認。propsにauth
が見当たらない、なぜ?
// routes/web.php
Route::get('/', function () {
return Inertia::render('Welcome', [
'canLogin' => Route::has('login'),
'canRegister' => Route::has('register'),
'laravelVersion' => Application::VERSION,
'phpVersion' => PHP_VERSION,
]);
});
理由はapp/Http/Middleware/HandleInertiaRequests.php
を見ると分かった。Inertia\Middleware
を継承しており、share
メソッドによってデフォルトのpropsを定義していた。その中にauth
があった。
return以降を見てみる。フラグメント(<>...</>
)やコンポーネント(<Head title="Welcome" />
)が使用されている。
export default function Welcome({ auth, laravelVersion, phpVersion }) {
return (
<>
<Head title="Welcome" />
{/* 省略 */}
</>
);
}
Inertiaの理解
HandleInertiaRequests
に定義された$rootView
によってルートになるviewファイル(Root Template)が決まるようだ。デフォルトはresources/views/app.blade.php
。
// app/Http/Middleware/HandleInertiaRequests.php
protected $rootView = 'app';
Inertia、Reactをマニュアルインストール
最初にBreezeパッケージで一緒にInertiaを導入したがもう少しInertiaを理解するために、Breezeを使わずにマニュアルでインストールしてみた。
サーバーサイドの設定
composer require inertiajs/inertia-laravel
composer.json
に依存関係が追加された。
"inertiajs/inertia-laravel": "^0.6.10",
次にRoot Templateの作成。app.blade.php
を作る。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
@vite('resources/js/app.js')
@inertiaHead
</head>
<body>
@inertia
</body>
</html>
Middlewareの作成
php artisan inertia:middleware
app/Http/Middleware/HandleInertiaRequests.php
が生成される。app/Http/Kernel.php
に登録する。
'web' => [
// ...
\App\Http\Middleware\HandleInertiaRequests::class,
],
クライアントサイドの設定(React)
npm install @inertiajs/react
composer.json
に依存関係が追加された。
"dependencies": {
"@inertiajs/react": "^1.0.11"
}
Viteの設定
一度Laravelのドキュメントに戻る
npm install --save-dev @vitejs/plugin-react
composer.json
に依存関係が追加された。
"devDependencies": {
"@vitejs/plugin-react": "^4.1.0",
vite.config.js
の設定 : configuring-vite
vite.config.js
にエントリポイントresources/js/app.jsx
を追加しreact()
で有効化する。
// vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [
laravel(['resources/js/app.jsx']),
react(),
],
server: {
host: true,
hmr: {
host: 'localhost',
},
},
});
app.blade.php
のheadに以下を追加する。
@viteReactRefresh
@vite('resources/js/app.jsx')
react-domを追加
react-dom
をインストール
npm install react-dom
composer.json
に依存関係が追加された。
"dependencies": {
"@inertiajs/react": "^1.0.11",
"react-dom": "^18.2.0"
テストページresources/js/Pages/Test.jsx
を作る
export default function Test() {
return (
<>
<h1>TestPage</h1>
<p>this is test</p>
</>
);
}
web.php
にInertiaでルート定義。
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
Route::get('/', function () {
return Inertia::render('Test');
});
npm run dev
でVite開発サーバーを起動してページを確認。上記テストページが表示されれば成功。
Userデータを表示する
ここから実践。Userモデルから取得したusersデータをIndex.jsx
にリストで表示させてみる。Seederでダミーデータ生成済みとする。
まずはweb.php
にルーティング設定
// routes/web.php
Route::get('users', [UserController::class, 'index'])->name('users.index');
UserController
にindex
メソッドを定義して、Inertia::render
メソッドを使う。
// app/Http/Controllers/UserController.php
public function index()
{
$users = User::all();
return Inertia::render('User/Index', [
'users' => $users,
]);
}
propsに渡したusers
はUserモデルを格納したCollectionである。
// resources/js/Pages/User/Index.jsx
export default function Index({ users }) {
const userList = users.map(user =>
<li key={user.id}>
{user.id} : {user.name}
</li>
);
return (
<ul>
{userList}
</ul>
);
}
UserTableに改良する
パスはresources/js/Pages/
からの相対パスで表記。
User/UserTable.jsx
を作成してテーブルをマークアップしてエクスポート。
// User/UserTable.jsx
export default function UserTable({ users }) {
return (
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>E-mail</th>
</tr>
</thead>
<tbody>
{users.map(user => (
<tr key={user.id}>
<td>{user.id}</td>
<td>{user.name}</td>
<td>{user.email}</td>
</tr>
))}
</tbody>
</table>
);
}
Index.jsx
でUserTable
をインポートして読み込む。
// User/Index.jsx
import UserTable from "./UserTable";
export default function Index({ users }) {
return (
<div>
<h1>User List</h1>
<UserTable users={users} />
</div>
);
}
独自のレイアウトを作りたい
スタイルはSCSSを使用する(過去のリポジトリから流用)
Layouts/AppLayout.jsx
を作成。
export default function App({ children }) {
return (
<>
<header className="layout-header">
<div className="header-container">
ヘッダー
</div>
</header>
<main className="layout-main">
<div className="main-container">
{children}
</div>
</main>
</>
);
}
User/Index.jsx
でインポートして使用。
import AppLayout from '@/Layouts/AppLayout';
import UserTable from "./UserTable";
export default function Index({ users }) {
return (
<AppLayout>
<h1 className="title title-h1">User List</h1>
<UserTable users={users} />
</AppLayout>
);
}
InertiaのPersistent layoutsでSPA実現
上記のUser/Index.jsx
をPersistent layoutsを実現するために書き換える。これで共通のAppLayout
部分はページ遷移しても維持される。例えばヘッダー部分などに適当にinputを置いてテキストを入力した状態でページ遷移してもinputは保持されていることがわかる。
import AppLayout from '@/Layouts/AppLayout';
import UserTable from "./UserTable";
const Index = ({ users }) => {
return (
<>
<h1 className="title title-h1">User List</h1>
<UserTable users={users} />
</>
);
}
Index.layout = page => <AppLayout children={page} />
export default Index
連載記事
- 【1日目】React初学者が1週間でどこまで出来るか挑戦
- 【2日目】React初学者が1週間でどこまで出来るか挑戦
- 【3日目】React初学者が1週間でどこまで出来るか挑戦