0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Laravel (Eloquent Model) → GraphQL → React のデータフローパターン完全解説

Last updated at Posted at 2025-09-29

はじめに

Laravel + GraphQL + React の構成では、バックエンドからフロントエンドへのデータ受け渡しにいくつかの代表的なパターンがあります。
この記事では、実際のプロジェクトでもよく使われる2つのパターンをコード例付きで解説します。


📋 目次

  1. パターン1: マスタデータ一括取得パターン
  2. パターン2: LazyQuery動的データ取得パターン

パターン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} />

動作フロー例

シナリオ: 履歴モーダルを開いたとき

  1. ユーザーが行をクリック → setHogehogeId(clickedId)
  2. LazyQuery実行 → useEffect 内で getDetail()
  3. GraphQL API呼び出し → hogehogeDetailmsHogehogeMaster を取得
  4. DBアクセス → SELECT * FROM hogehoge ...
  5. React更新 → UI反映

LazyQuery vs useQuery 比較

項目 LazyQuery useQuery
実行タイミング 手動トリガー 自動実行
初期実行 されない される
条件分岐 柔軟 難しい
パフォーマンス 効率的 無駄な通信あり
用途 動的データ 静的データ

ベストプラクティス

  1. エラーハンドリング
if (error) {
    console.error(error.graphQLErrors)
    console.error(error.networkError)
}
  1. ローディング制御
{loading && <Spinner />}
{!loading && data && <HogeDetail data={data} />}
  1. キャッシュ戦略
useDetailLazyQuery({
    fetchPolicy: 'cache-first',
})
  1. 変数の動的更新
getDetail({ variables: { id: userId, search: keyword } })

まとめ (LazyQuery編)

  • 実行タイミングを自由にコントロール可能
  • 不要なAPI呼び出しを排除
  • 条件に応じた動的データ取得が可能
  • ユーザー操作に応じたレスポンシブな動作

LazyQueryを使うことで、高パフォーマンスで使いやすい業務システムが構築可能です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?