👏
Laravel Fragments - livewireを使わずに局所動的ページ更新
Laravel Fragments - 動的ページ更新のための新機能
Laravel Fragmentsは、ページの特定部分のみを更新できる新しいBlade機能です。AJAXやJavaScriptフレームワークに依存せずに、動的なユーザー体験を提供します。
概要
Fragmentsを使用すると、ページ全体をリロードすることなく、特定のセクションのみを更新できます。これにより、よりスムーズなユーザー体験と、サーバーリソースの効率的な使用が可能になります。
基本的な使用方法
Fragmentの定義
{{-- resources/views/products/index.blade.php --}}
@extends('layouts.app')
@section('content')
<h1>商品一覧</h1>
@fragment('product-list')
<div class="products">
@foreach($products as $product)
<div class="product-item">
<h3>{{ $product->name }}</h3>
<p>¥{{ number_format($product->price) }}</p>
</div>
@endforeach
</div>
{{ $products->links() }}
@endfragment
@endsection
コントローラーでの処理
class ProductController extends Controller
{
public function index(Request $request)
{
$products = Product::paginate(10);
// Fragmentリクエストの場合
if ($request->wantsFragment('product-list')) {
return view('products.index', compact('products'))
->fragment('product-list');
}
// 通常のリクエスト
return view('products.index', compact('products'));
}
}
JavaScriptとの統合
自動Fragment更新
// Laravel Fragmentsのヘルパーを使用
document.addEventListener('DOMContentLoaded', function() {
// ページネーションリンクの自動Fragment化
Fragment.hijackLinks('.pagination a', 'product-list');
// フォーム送信の自動Fragment化
Fragment.hijackForm('#filter-form', 'product-list');
});
手動でのFragment取得
// Fetchを使用した手動更新
async function updateProductList(page = 1) {
const response = await fetch(`/products?page=${page}`, {
headers: {
'X-Fragment': 'product-list',
'Accept': 'text/html'
}
});
if (response.ok) {
const html = await response.text();
document.getElementById('product-list').outerHTML = html;
}
}
高度な使用例
複数のFragmentの同時更新
{{-- カートページ --}}
@fragment('cart-items')
@foreach($cartItems as $item)
<div class="cart-item">
{{ $item->product->name }}
<input type="number"
name="quantity"
value="{{ $item->quantity }}"
data-update-fragment="cart-items,cart-summary">
</div>
@endforeach
@endfragment
@fragment('cart-summary')
<div class="summary">
<p>小計: ¥{{ number_format($subtotal) }}</p>
<p>税込: ¥{{ number_format($total) }}</p>
</div>
@endfragment
条件付きFragment
public function update(Request $request, Product $product)
{
$product->update($request->validated());
if ($request->wantsFragment()) {
// 成功メッセージを含むFragmentを返す
return view('products.show', compact('product'))
->fragment($request->fragment())
->with('success', '商品が更新されました');
}
return redirect()->route('products.show', $product)
->with('success', '商品が更新されました');
}
ネストされたFragment
@fragment('comments-section')
<div class="comments">
<h3>コメント ({{ $comments->count() }})</h3>
@fragment('comments-list')
@foreach($comments as $comment)
<div class="comment">
<strong>{{ $comment->user->name }}</strong>
<p>{{ $comment->body }}</p>
</div>
@endforeach
@endfragment
@fragment('comment-form')
<form method="POST" action="{{ route('comments.store') }}">
@csrf
<textarea name="body"></textarea>
<button type="submit">投稿</button>
</form>
@endfragment
</div>
@endfragment
Livewireとの比較
機能 | Fragments | Livewire |
---|---|---|
サーバーサイドレンダリング | ✓ | ✓ |
JavaScriptの必要性 | 最小限 | 必須 |
リアルタイム更新 | 手動 | 自動 |
学習曲線 | 低い | 中程度 |
ファイルサイズ | 小さい | 大きい |
パフォーマンスの考慮事項
- キャッシング: Fragmentsは個別にキャッシュ可能
return view('products.index', compact('products'))
->fragment('product-list')
->remember(300); // 5分間キャッシュ
- 遅延読み込み: スクロール時の自動読み込み
Fragment.lazyLoad('.load-more', 'next-products');
- デバウンス: 頻繁な更新の制御
Fragment.debounce('#search-input', 'search-results', 300);
ベストプラクティス
-
Fragment名の命名規則: ケバブケースを使用(
user-profile
、cart-summary
) - エラーハンドリング: Fragment更新失敗時のフォールバック
- アクセシビリティ: スクリーンリーダー向けのARIA属性
- SEO対策: 初回読み込みは完全なHTMLを返す
まとめ
Laravel Fragmentsは、モダンなWebアプリケーションに必要な動的更新機能を、シンプルかつ効率的に実装する方法を提供します。複雑なJavaScriptフレームワークを導入することなく、優れたユーザー体験を実現できます。
出典: Laravel News Blog
Discussion