معالجة الأخطاء
في الفصل السابق، تعلمت كيفية تعديل البيانات باستخدام إجراءات الخادم (Server Actions). لنرى الآن كيف يمكنك معالجة الأخطاء بسلاسة باستخدام عبارات try/catch
في جافاسكريبت وواجهات برمجة التطبيقات (APIs) الخاصة بـ Next.js للاستثناءات غير المعالجة.
إضافة try/catch
إلى إجراءات الخادم
أولاً، لنضيف عبارات try/catch
الخاصة بجافاسكريبت إلى إجراءات الخادم الخاصة بك للسماح لك بمعالجة الأخطاء بسلاسة.
إذا كنت تعرف كيفية القيام بذلك، خذ بضع دقائق لتحديث إجراءات الخادم الخاصة بك، أو يمكنك نسخ الكود أدناه:
لاحظ كيف يتم استدعاء redirect
خارج كتلة try/catch
. هذا لأن redirect
يعمل عن طريق طرح خطأ، والذي سيتم التقاطه بواسطة كتلة catch
. لتجنب ذلك، يمكنك استدعاء redirect
بعد try/catch
. سيكون redirect
قابلاً للوصول فقط إذا نجحت try
.
نقوم بمعالجة هذه الأخطاء بسلاسة عن طريق التقاط مشكلة قاعدة البيانات، وإعادة رسالة مفيدة من إجراء الخادم الخاص بنا.
ماذا يحدث إذا كان هناك استثناء غير معالج في إجراءك؟ يمكننا محاكاة ذلك عن طريق طرح خطأ يدويًا. على سبيل المثال، في إجراء deleteInvoice
، اطرح خطأ في أعلى الدالة:
export async function deleteInvoice(id: string) {
throw new Error('Failed to Delete Invoice');
// كود غير قابل للتنفيذ
await sql`DELETE FROM invoices WHERE id = ${id}`;
revalidatePath('/dashboard/invoices');
}
عند محاولة حذف فاتورة، يجب أن ترى الخطأ على localhost. عند الانتقال إلى الإنتاج، تريد أن تعرض رسالة أكثر سلاسة للمستخدم عندما يحدث شيء غير متوقع.
هنا يأتي دور ملف error.tsx
في Next.js. تأكد من إزالة هذا الخطأ المضاف يدويًا بعد الاختبار وقبل الانتقال إلى القسم التالي.
معالجة جميع الأخطاء باستخدام error.tsx
يمكن استخدام ملف error.tsx
لتعريف حدود واجهة المستخدم (UI boundary) لقطاع مسار (route segment). يعمل كـ شبكة أمان للاستثناءات غير المتوقعة ويسمح لك بعرض واجهة مستخدم بديلة للمستخدمين.
داخل مجلد /dashboard/invoices
الخاص بك، أنشئ ملفًا جديدًا يسمى error.tsx
والصق الكود التالي:
'use client';
import { useEffect } from 'react';
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
// اختياريًا: تسجيل الخطأ في خدمة تقارير الأخطاء
console.error(error);
}, [error]);
return (
<main className="flex h-full flex-col items-center justify-center">
<h2 className="text-center">حدث خطأ ما!</h2>
<button
className="mt-4 rounded-md bg-blue-500 px-4 py-2 text-sm text-white transition-colors hover:bg-blue-400"
onClick={
// محاولة الاسترداد عن طريق إعادة عرض مسار الفواتير
() => reset()
}
>
حاول مرة أخرى
</button>
</main>
);
}
هناك بعض الأشياء التي ستلاحظها في الكود أعلاه:
- "use client" - يحتاج
error.tsx
إلى أن يكون مكون عميل (Client Component). - يقبل خاصيتين (props):
error
: هذا الكائن هو نسخة من كائنError
الأصلي في جافاسكريبت.reset
: هذه دالة لإعادة تعيين حدود الخطأ. عند التنفيذ، ستقوم الدالة بمحاولة إعادة عرض قطاع المسار.
عند محاولة حذف فاتورة مرة أخرى، يجب أن ترى واجهة المستخدم التالية:

معالجة أخطاء 404 باستخدام دالة notFound
طريقة أخرى يمكنك من خلالها معالجة الأخطاء بسلاسة هي باستخدام دالة notFound
. بينما يكون error.tsx
مفيدًا للاستثناءات غير المعالجة، يمكن استخدام notFound
عندما تحاول جلب مورد غير موجود.
على سبيل المثال، قم بزيارة http://localhost:3000/dashboard/invoices/2e94d1ed-d220-449f-9f11-f0bbceed9645/edit.
هذا UUID مزيف غير موجود في قاعدة البيانات الخاصة بك.
سترى على الفور أن error.tsx
يبدأ العمل لأن هذا مسار فرعي لـ /invoices
حيث يتم تعريف error.tsx
.
ومع ذلك، إذا كنت تريد أن تكون أكثر تحديدًا، يمكنك عرض خطأ 404 لإخبار المستخدم أن المورد الذي يحاول الوصول إليه لم يتم العثور عليه.
يمكنك التأكد من أن المورد غير موجود بالذهاب إلى دالة fetchInvoiceById
في data.ts
، وتسجيل الفاتورة التي تم إرجاعها في الكونسول:
export async function fetchInvoiceById(id: string) {
try {
// ...
console.log(invoice); // الفاتورة هي مصفوفة فارغة []
return invoice[0];
} catch (error) {
console.error('خطأ في قاعدة البيانات:', error);
throw new Error('فشل في جلب الفاتورة.');
}
}
الآن بعد أن عرفت أن الفاتورة غير موجودة في قاعدة البيانات الخاصة بك، دعنا نستخدم notFound
لمعالجتها. انتقل إلى /dashboard/invoices/[id]/edit/page.tsx
، واستورد { notFound }
من 'next/navigation'
.
ثم، يمكنك استخدام شرط لاستدعاء notFound
إذا لم تكن الفاتورة موجودة:
import { fetchInvoiceById, fetchCustomers } from '@/app/lib/data';
import { notFound } from 'next/navigation';
export default async function Page(props: { params: Promise<{ id: string }> }) {
const params = await props.params;
const id = params.id;
const [invoice, customers] = await Promise.all([
fetchInvoiceById(id),
fetchCustomers(),
]);
if (!invoice) {
notFound();
}
// ...
}
ثم، لعرض واجهة مستخدم الخطأ للمستخدم، أنشئ ملف not-found.tsx
داخل مجلد /edit
.

داخل ملف not-found.tsx
، الصق الكود التالي:
import Link from 'next/link';
import { FaceFrownIcon } from '@heroicons/react/24/outline';
export default function NotFound() {
return (
<main className="flex h-full flex-col items-center justify-center gap-2">
<FaceFrownIcon className="w-10 text-gray-400" />
<h2 className="text-xl font-semibold">404 غير موجود</h2>
<p>تعذر العثور على الفاتورة المطلوبة.</p>
<Link
href="/dashboard/invoices"
className="mt-4 rounded-md bg-blue-500 px-4 py-2 text-sm text-white transition-colors hover:bg-blue-400"
>
العودة
</Link>
</main>
);
}
قم بتحديث المسار، ويجب أن ترى الآن واجهة المستخدم التالية:

هذا شيء يجب تذكره، notFound
سيكون له الأسبقية على error.tsx
، لذا يمكنك اللجوء إليه عندما تريد معالجة أخطاء أكثر تحديدًا!
قراءة إضافية
لمعرفة المزيد عن معالجة الأخطاء في Next.js، راجع الوثائق التالية: