ازاي تخلي الـ Dialogs والـ Modals تفتح كـ Routes مستقلة في Inertia.js؟
يا هلا بيك يا باشمهندس في مقال جديد من سلسلة شروحات تطوير الويب (Web Development). تعالّ نتخيل مع بعض السيناريو ده: قاعد شغال على مشروع وبناءً على طلب العميل، عملت نافذة منبثقة أو ديالوج (Dialog / Modal) عشان يظهر تفاصيل منتج معين أو نموذج إضافة بيانات. الدنيا تمام وشكلها شيك جداً، بس فجأة.. اليوزر حب يعمل ريفريش (Refresh) للصفحة، أو خد اللينك (URL) بعته لصاحبه، أو حتى داس على زرار الرجوع (Back Button) في المتصفح.. إيه اللي بيحصل؟
بكل بساطة، النافذة بتقفل، اليوزر بيرجع للصفحة الرئيسية، وبيسأل نفسه: "هو راح فين اللينك اللي كنت بكلمه فيه؟". الوجع ده مألوف لكل مبرمج فرونت إند أو فول ستاك بيتعامل مع الـ Single Page Applications (SPAs). بس ما تقلقش، في المقال ده هناخد بايدينا خطوة بخطوة عشان نتعلم إزاي نستخدم الـ Dialogs والـ Modals كـ Routes مستقلة في إنرتيا (Inertia.js)، بحيث كل مودال يكون ليه رابط خاص بيه، يسهل مشاركته، ويدعم زرار الرجوع بكل سهولة.
Table of contents [Show]
ليه أصلاً نحتاج نخلي الـ Modal يشتغل كـ Route مستقل؟
زمان، لما كنا بنحب نعمل مودال، كنا بنعتمد بالكامل على الحالة المحلية (Local State) زي الـ useState في رياكت أو الـ ref في فيو (Vue). الحالة دي بتعيش جوه الصفحة الحالية وبس. أول ما الصفحة تتحدث، الحالة دي بتموت.
لما نربط الـ Dialog بـ مسار حقيقي (URL / Route)، إحنا بنستفاد الآتي:
- سهولة المشاركة (URL Sharing): اليوزر يقدر يبعت اللينك لزميله، فيفتح نفس المودال مباشرة من غير ما يضطر يدور عليه جوه الموقع.
- تجربة استخدام احترافية (UX): استخدام زرار الرجوع (Browser Back Button) بيقفل المودال بس مش بيطلعك بره الصفحة، ودي تجربة بتخلي تطبيقك تحس إنه تطبيق موبايل أصلي (Native App).
- التوافق مع السيرفر (Server-side Routing): الاستفادة الكاملة من قوة لارا لافيل (Laravel) في معالجة الطلبات وإرجاع البيانات المناسبة لنفس الـ Endpoint.
فكرة الشغل: إزاي إنرتيا (Inertia.js) بتعالج الموضوع ده؟
إنرتيا بتتميز إنها بتربط الـ Backend بالـ Frontend من غير ما تحتاج تساهم في بناء API منفصل. عشان نعمل مودال بـ URL خاص بيه، الفكرة باختصار إن الـ Route بتاعنا في السيرفر هيرجع نفس الصفحة الأساسية (Base Page)، بس مع تمرير بروب (Prop) إضافي بيعرف الفرونت إند إن المودال الفلاني المفروض يفتح وفي قلبه البيانات بتاعته.
يعني لو عندنا جدول للمستخدمين (Users Table)، فالـ URL العادي هيكون /users، ولو اليوزر ضغط على مستخدم معين عشان يشوف تفاصيله، الـ URL هيتغير لـ /users/5. السيرفر هنا هيبعت نفس صفحة جدول المستخدمين، بس مع داتا المستخدم رقم 5، والفرونت إند أول ما يشوف الداتا دي، يفتح الـ Modal أو الـ Dialog أوتوماتيك!
التطبيق العملي: خطوة بخطوة باستخدام Laravel و Inertia مع Vue أو React
تعالوا نطبق الكلام ده بشكل عملي. هنفترض إننا شغالين بمشروع لارا لافيل مع إنرتيا. الخطوات اللي جاية دي هي المفتاح السحري للموضوع:
1. إعداد الـ Routes في Laravel
أول خطوة هي تعريف الـ Routes صح. محتاجين راوتر بيعرض الصفحة الرئيسية، وراوتر تاني (أو نفس الراوتر بس بمعالجة ذكية) بيفتح المودال.
// routes/web.php
use App\Http\Controllers\UserController;
Route::get('/users', [UserController::class, 'index'])->name('users.index');
Route::get('/users/{user}', [UserController::class, 'show'])->name('users.show');
2. كتابة الـ Controller
في الـ Controller، هنخلي الـ Method الخاصة بعرض المستخدم الفردي ترجع نفس الصفحة الرئيسية بس مبعوث معاها بيانات المستخدم المطلوب عرضه جوه المودال، وممكن نبعت كمانフラغ (Flag) يقول للمودال إنه مفروض يفتح.
// app/Http\Controllers\UserController.php
namespace App\Http\Controllers;
use App\Models\User;
use Inertia\Inertia;
class UserController extends Controller
{
public function index()
{
return Inertia::render('Users/Index', [
'users' => User::all(),
'selectedUser' => null // في الحالة العادية مفيش يوزر محدد
]);
}
public function show(User $user)
{
// بنرجع نفس الصفحة بس بنبعت اليوزر المختار
return Inertia::render('Users/Index', [
'users' => User::all(),
'selectedUser' => $user // ده اللي هيفتح المودال
]);
}
}
3. التعامل مع الفرونت إند (Frontend Integration)
دلوقتي في صفحة الـ Vue أو React، هنستقبل الـ selectedUser كـ Prop. لو الـ Prop ده موجود، هنعرض الـ Dialog. ولمن اليوزر يقفل المودال، هنعمل زيارة (Visit) للـ Route العادي (مثلاً /users) باستخدام ميزة الـ preserveState عشان الصفحة مبتعملش Reload كامل وتكون السرعة رهيبة.
مثال مبسط بطريقة تفكير الكود:
// مثال تخيلي داخل مكون VueJS
<template>
<div>
<h1>قائمة المستخدمين</h1>
<!-- جدول المستخدمين -->
<div v-for="user in users" :key="user.id">
<Link :href="route('users.show', user.id)">{{ user.name }}</Link>
</div>
<!-- الـ Dialog أو الـ Modal -->
<Modal :show="selectedUser !== null" @close="closeModal">
<div v-if="selectedUser">
<h2>تفاصيل المستخدم: {{ selectedUser.name }}</h2>
<p>البريد الإلكتروني: {{ selectedUser.email }}</p>
</div>
</Modal>
</div>
</template>
<script setup>
import { router, Link } from '@inertiajs/vue3';
defineProps({
users: Array,
selectedUser: Object
});
const closeModal = () => {
// بنرجع للرابط الأساسي من غير ما نعمل Reload كامل للصفحة
router.visit('/users', {
preserveScroll: true,
});
};
</script>
نصائح ذهبية لتجربة استخدام خالية من المشاكل (Best Practices)
عشان تضمن إن الأداء يكون عالي ومفيش أي bugs تظهر معاك، خد بالك من النقط دي:
- الحفاظ على التمرير (Preserve Scroll): دايماً استخدم خيار
preserveScroll: trueلما اليوزر يقفل المودال، عشان مكان ما كان واقف في الجدول ما يتغيرش ويروح فوق خالص. - التحميل الكسول (Lazy Loading): لو بيانات المودال ثقيلة، يفضل تجيبها عن طريق الـ Partial Reloads في إنرتيا بدل ما تحمل كل بيانات الصفحة في كل مرة.
- الانيميشن (Transitions): ضيف تأثيرات حركية (Transitions) لطيفة عند فتح وقفل المودال عشان تخلي التجربة غاية في النعومة.
خاتمة ونصيحة أخوية
استخدام الـ Dialogs والـ Modals كـ Routes مستقلة في Inertia.js بينقل تطبيقك من مجرد تطبيق عادي لتطبيق احترافي بينافس التطبيقات الكبيرة في سلاسته وسهولة استخدامه. في الأول ممكن تحس إنها لفة شوية، ولكن مع التكرار هتلاقي الموضوع بيتم في ثواني وبيديك تحكم كامل في الـ History والـ URL.
نصيحة أخوية: ما تتسرعش في تعقيد الكود من أول مرة. ابدأ بمثال بسيط زي اللي شرحناه، جربه بايدك، واكسر شوية كود لحد ما تفهم ازاي إنرتيا بتدير الحالة والـ History. الاستمرارية هي سر التطور، وتذكر دايماً إن التفاصيل الصغيرة هي اللي بتفرق بين المبرمج الهاوي والمبرمج المحترف! بالتوفيق يا بطل.