はじめに
Laravel + GraphQL + React の構成では、バックエンドからフロントエンドへのデータ受け渡しにいくつかの代表的なパターンがあります。
この記事では、実際のプロジェクトでもよく使われる2つのパターンをコード例付きで解説します。
📋 目次
パターン1: マスタデータ一括取得パターン
用途: セレクトボックスのオプション、設定値など、変更頻度の低い静的データ
アーキテクチャ図
[DB] ms_hogehoge_master
↓
[Laravel Model] MsHogehogeMaster
↓
[GraphQL Schema] 型定義
↓
[GraphQL Query] Fragment + Query定義
↓
[Apollo Client] useLazyQuery
↓
[React Component] Select options
1. Database & Laravel Model
// Migration
Schema::create('ms_hogehoge_master', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
// Model
class MsHogehogeMaster extends Model
{
protected $fillable = ['name'];
}
2. GraphQL Schema & Resolver
type MsHogehogeMaster {
id: Int!
name: String!
created: DateTime!
modified: DateTime
}
3. GraphQL Query定義
// query.ts
export const DETAIL_QUERY = gql`
query detail($id: Int!, $hogehogeId: Int!) {
msHogehogeMaster {
...MsHogehogeMaster
}
hogehogeDetail(id: $id) {
# 実際の詳細データ
}
}
`;
export const MsHogehogeMaster = gql`
fragment MsHogehogeMaster on MsHogehogeMaster {
id
name
}
`;
4. React Containerでのデータ取得
const HogeContainer = () => {
const [getHogehogeDetail, { data, loading }] = useDetailLazyQuery({
variables: { id: hogehogeId },
nextFetchPolicy: 'cache-first',
});
const masterList = data?.msHogehogeMaster?.map(item => ({
value: item.id,
label: item.name,
}));
return <HogePresentation masterList={masterList} />;
};
5. Presentation Component
const HogePresentation = ({ masterList }) => (
<Select
options={masterList}
placeholder="選択してください"
onChange={handleChange}
/>
);
特徴
- 一度の取得で複数マスタを取得可能
- Fragment活用で再利用性が高い
-
cache-first
で高速表示
パターン2: LazyQuery動的データ取得パターン
用途: ユーザー操作をトリガーとした動的データ取得
const HogeDetailContainer = () => {
const [getHogehoge, { data, loading }] = useHogehogeDetailLazyQuery({
variables: { id: hogehogeId },
nextFetchPolicy: 'cache-first',
});
useEffect(() => {
if (hogehogeId) {
getHogehoge();
}
}, [hogehogeId]);
return <HogeDetail data={data} loading={loading} />;
};
特徴
- 遅延実行で必要なときだけ取得
- 条件付き実行が可能
- UX向上につながる
LazyQuery完全フロー解説
実装の全体像
Step 1: LazyQuery初期化
const [getDetail, { data, loading, error }] = useDetailLazyQuery({
variables: {
id: hogehogeId ? Number(hogehogeId) : 0,
userId: userId ? Number(userId) : 0,
},
nextFetchPolicy: 'cache-first',
})
-
[実行関数, レスポンス情報]
が返る -
variables
: クエリに渡すパラメーター -
nextFetchPolicy
: キャッシュ戦略
Step 2: トリガー条件の設定
useEffect(() => {
if (hogehogeId) {
getDetail();
}
}, [hogehogeId]);
useEffect(() => {
getDetail();
}, []);
実行パターン:
- 条件付き実行: 必要な値が確定したら実行
- 初回実行: コンポーネント読み込み時に1回実行
- 再実行: 依存値変更時に再実行
Step 3: GraphQL API実行フロー
[LazyQuery実行]
↓
[Apollo Client] variables付きリクエスト
↓
[Laravel GraphQL API] Query処理
↓
[Eloquent Model] DBアクセス
↓
[Database] SQL実行
↓
[GraphQL Response] JSONレスポンス
↓
[Apollo Client] データ受信・キャッシュ
↓
[React State] data更新
↓
[Component Re-render] UI更新
Step 4: レスポンスデータの活用
if (loading) return <Spinner />
if (error) console.error(error)
const masterList = data?.msHogehogeMaster?.map(item => ({
value: item.id,
label: item.name,
}))
return <HogeDetail data={data} masterList={masterList} />
動作フロー例
シナリオ: 履歴モーダルを開いたとき
- ユーザーが行をクリック →
setHogehogeId(clickedId)
- LazyQuery実行 →
useEffect
内でgetDetail()
- GraphQL API呼び出し →
hogehogeDetail
とmsHogehogeMaster
を取得 - DBアクセス →
SELECT * FROM hogehoge ...
- React更新 → UI反映
LazyQuery vs useQuery 比較
項目 | LazyQuery | useQuery |
---|---|---|
実行タイミング | 手動トリガー | 自動実行 |
初期実行 | されない | される |
条件分岐 | 柔軟 | 難しい |
パフォーマンス | 効率的 | 無駄な通信あり |
用途 | 動的データ | 静的データ |
ベストプラクティス
- エラーハンドリング
if (error) {
console.error(error.graphQLErrors)
console.error(error.networkError)
}
- ローディング制御
{loading && <Spinner />}
{!loading && data && <HogeDetail data={data} />}
- キャッシュ戦略
useDetailLazyQuery({
fetchPolicy: 'cache-first',
})
- 変数の動的更新
getDetail({ variables: { id: userId, search: keyword } })
まとめ (LazyQuery編)
- 実行タイミングを自由にコントロール可能
- 不要なAPI呼び出しを排除
- 条件に応じた動的データ取得が可能
- ユーザー操作に応じたレスポンシブな動作
LazyQueryを使うことで、高パフォーマンスで使いやすい業務システムが構築可能です。