1. Inertia.js Setup
composer require inertiajs/inertia-laravel
npm install @inertiajs/vue3
// Controller — trả về Inertia response
use Inertia\Inertia;
class ProductController extends Controller
{
public function index()
{
return Inertia::render('Products/Index', [
'products' => Product::with('category')->paginate(20),
'filters' => request()->only(['search', 'category']),
]);
}
public function store(StoreProductRequest $request)
{
Product::create($request->validated());
return redirect()->route('products.index')
->with('success', 'Sản phẩm đã được tạo!');
}
}
2. Vue Pages
<!-- resources/js/Pages/Products/Index.vue -->
<script setup>
import { Head, Link, router } from '@inertiajs/vue3';
import { ref, watch } from 'vue';
const props = defineProps({
products: Object,
filters: Object,
});
const search = ref(props.filters.search ?? '');
watch(search, (value) => {
router.get('/products', { search: value }, {
preserveState: true,
replace: true,
});
});
</script>
<template>
<Head title="Sản phẩm" />
<input v-model="search" placeholder="Tìm kiếm..." />
<div v-for="product in products.data" :key="product.id">
<Link :href="`/products/${product.slug}`">
{{ product.name }} - {{ product.price }}đ
</Link>
</div>
</template>
3. Inertia Forms
<script setup>
import { useForm } from '@inertiajs/vue3';
const form = useForm({
name: '',
price: 0,
description: '',
image: null,
});
function submit() {
form.post('/products', {
forceFormData: true,
onSuccess: () => form.reset(),
});
}
</script>
<template>
<form @submit.prevent="submit">
<input v-model="form.name" />
<span v-if="form.errors.name">{{ form.errors.name }}</span>
<button :disabled="form.processing">Lưu</button>
</form>
</template>
4. Shared Data
// Middleware HandleInertiaRequests
public function share(Request $request): array
{
return [
...parent::share($request),
'auth' => ['user' => $request->user()],
'flash' => ['success' => $request->session()->get('success')],
];
}
5. Livewire vs Inertia
| Features | Livewire | Inertia |
|---|---|---|
| Frontend | Blade + Alpine.js | Vue/React |
| SPA Feel | Good | Very good |
| Learning curve | Low | Average |
| JS ecosystem | Limitations | Full |
| SSR | Automatically | Need setup |
Next article: Testing in Laravel.