フロントエンド的な画面の作成方法
Inertiaの使い方の基本を紹介したところで、次にフロントエンド的な画面の作り方を、図4の画面を使いながら紹介していきます。この画面は、前回の図2と同じ画面です。といっても、実は、前節の基本的なコーディング方法からほとんど差はありません。というのは、画面部分に使っているVueが、そもそもフロントエンド用のフレームワークだからです。具体的にみていきましょう。
モデルの利用も従来のLaravelプロジェクトと同様
まずは、コントローラクラスのコードから見ていきます。
画面に表示するカクテルリストデータというのは、前回同様に、モデルを利用しますが、前節の通りコントローラクラス内でデータを用意するコードというのは、従来のLaravelプロジェクトと差はありません。
したがって、リスト4のコードとなります。
class CocktailController extends Controller
{
public function showCocktailList()
{
$data["cocktailList"] = Cocktail::all(); // (1)
return Inertia::render("cocktail/CocktailList", $data); // (2)
}
}
リスト4の(1)でCocktailモデルのall()メソッドにより取得した全カクテルリストデータを、$data連想配列のキーcocktailListとして登録しています。そして、この$dataを第2引数としてInertia::render()メソッドを実行し、その結果をリターンしているのが(2)です。
フロントエンド的な挙動はVueの仕組みを活用
次に、その(2)の第1引数として指定しているコンポーネントであるcocktail/CocktailList.vueファイルをresources/js/pagesフォルダ内に作成します。これは、リスト5の内容となります。
<script setup lang="ts">
import {ref} from "vue";
//Cocktailインターフェースを定義。
interface Cocktail { // (1)
id: number; // (1)
name: string; // (1)
price: number; // (1)
} // (1)
//Propsインターフェースを定義。
interface Props { // (2)
cocktailList: Cocktail[]; // (2)
} // (2)
//Propsの取得。
const props = defineProps<Props>(); // (3)
//詳細情報セクションの表示非表示切替用変数の用意。
const detailSection = ref(false); // (4)
//詳細表示セクションに表示するCocktailオブジェクト用変数の用意。
const selectedCocktail = ref<Cocktail|null>(null); // (5)
//詳細表示セクションを表示させるメソッド。
const showDetail = (id: number) => { // (6)
//詳細表示セクションに表示するカクテルデータを取得。
selectedCocktail.value = props.cocktailList.find( // (7)
(cocktailInList: Cocktail) => { // (7)
return cocktailInList.id === id; // (7)
} // (7)
); // (7)
//詳細表示セクションを表示に変更。
detailSection.value = true; // (8)
};
//詳細表示セクションを非表示にするメソッド。
const closeDetail = () => { // (9)
//詳細表示セクションを非表示に変更。
detailSection.value = false; // (10)
//詳細表示セクションに表示するカクテルデータをnullに変更。
selectedCocktail.value = null; // (11)
};
</script>
<template>
<h1>カクテル管理</h1>
<section>
<h2>カクテルリスト</h2>
<ul>
<li v-for="cocktail in cocktailList" v-bind:key="cocktail.id"><a v-on:click="showDetail(cocktail.id)">{{cocktail.name}}</a></li> // (12)
</ul>
<p>
<a href="#">カクテルの追加はこちら</a> // (13)
</p>
</section>
<section v-if="detailSection"> // (14)
<h2>{{selectedCocktail?.name}}の詳細</h2> // (15)
<dl>
<dt>ID</dt>
<dd>{{selectedCocktail?.id}}</dd> // (15)
<dt>名前</dt>
<dd>{{selectedCocktail?.name}}</dd> // (15)
<dt>金額</dt>
<dd>{{selectedCocktail?.price}}</dd> // (15)
</dl>
<button v-on:click="closeDetail">閉じる</button> // (16)
</section>
</template>
図4(すなわち、前回の図1、および、図2)の最大の特徴は、リストをクリックすると詳細情報セクションが表示されることです。また、そのセクション内の[閉じる]ボタンをクリックすることで、詳細情報セクションそのものが画面から消えます。
リスト5で、この処理をどのように実現しているかと言えば、特別なことはなく、(4)で用意したリアクティブな変数detailSectionのtrue/falseを切り替えているだけで、それに連動するように(14)のv-ifが作用し、詳細情報セクションそのものの表示・非表示が切り替わります。この仕組みはLaravelのものではなく、Vueの仕組みそのものです。
trueへの切り替え処理は(12)のリストの各aタグに設定したv-on:clickのメソッドshowDetail内で行っている(8)が該当します。一方、falseへの切り替え処理は(16)のbuttonタグに設定した同じくv-on:clickのメソッドcloseDetail内で行っている(10)が該当します。
このように、フロントエンド的な画面挙動は、Inertiaの場合はVueに任せることができます。
モデルに対応したインターフェースを定義
さて、リスト5の一番肝要な部分を紹介したので、残りのコードに関して軽く補足しておきます。
カクテルリスト画面に表示するリストデータは、リスト4の(1)でCocktailモデルにより取得したデータベース上のリストデータです。そして、そのリストデータ1件分のデータ項目は、Cocktailモデルオブジェクトそのものであり、もちろん、これはPHPのデータ構造となっています。
一方、VueなどのフロントエンドはTypeScriptでのコーディングであり、言語が違うので、モデルオブジェクトのデータ構造をそのまま引き継ぐことはできません。
そこで、Vueの方では別立てでCocktailモデル1件分のデータ構造を定義しておき、それを利用することで、データの不整合を未然に防ぐようにします。それが、リスト5の(1)のCocktailインターフェースです。もちろん、このようなインターフェースは、通常は、各コンポーネント内で定義するのではなく、アプリケーション全体で一元管理します。ここでは説明の関係上、コンポーネントに定義していることをご了承ください。
このように定義したCocktailインターフェースを利用して、(2)のように、PropsのcocktailList、すなわち、コントローラから渡されるデータの型をCocktailの配列としています。これにより、Laravel(PHP)側のCocktailモデルオブジェクトとVue(TypeScript)側のCocktailオブジェクトが同一データ項目であることが保証されます。
カクテル詳細情報で表示するデータはnullの可能性を考慮
また、このCocktailインターフェースは、カクテル詳細情報セクションで表示する1件分のカクテル情報であるリスト5の(5)のselectedCocktailでも型指定として利用しています。ただし、カクテル詳細情報セクションが非表示の場合は、データが存在せず、selectedCocktailをnullとする必要があります。
実際、カクテル詳細情報セクションを閉じる処理メソッドである(9)の内部では(11)でnullを代入しています。そのため、selectedCocktailのデータ型をCocktailとnullのユニオン型としています。それに合わせて、(15)の表示部分では、selectedCocktail?.という記述(オプショナルチェーン)でnullの場合に対応しています。
カクテル詳細情報表示で表示するデータはリストデータから取得
最後に、そのselectedCocktailを取得しているコードは(7)が該当します。カクテルリストの各カクテル名をクリックしたときの処理メソッドである(6)で、引数として渡されたカクテルのIDを元に、(3)のPropsとして渡されたcocktailListから該当Cocktailオブジェクトを探し出さなければなりません。具体的には(7)のコードが該当し、配列のfind()メソッドを利用し、各要素のidプロパティが引数と合致するものを探し出しています。
このように、先述のとおり、Inertiaを利用した場合、フロントエンド部分の処理は、すべてVueのコーディングそのものとなります。
ところで、(13)のカクテル情報追加画面への遷移に関しては、まともなリンクパスが記述されていません。このInertiaを利用したLaravelプロジェクトでの画面遷移に関しては、次回紹介します。
まとめ
Laravelのフロントエンド的画面作成方法を紹介する連載の第3回目は、いかがでしたでしょうか。
今回は、InertiaとVueを組み合わせたプロジェクトにおけるコーディングの基礎的な内容を紹介しました。本連載も次回が最後です。その最後として、先述の通り、Inertiaによる画面遷移およびフォームデータの取り扱いを紹介します。
