الصفحات والتخطيطات

نوصي بقراءة صفحات أساسيات التوجيه وتحديد المسارات قبل المتابعة.

تسمح لك الملفات الخاصة layout.js، page.js، و template.js بإنشاء واجهة مستخدم لـ مسار. سيرشدك هذا الصفحة حول كيفية ومتى تستخدم هذه الملفات الخاصة.

الصفحات

الصفحة هي واجهة مستخدم فريدة لمسار. يمكنك تعريف صفحة عن طريق تصدير مكون افتراضي من ملف page.js.

على سبيل المثال، لإنشاء صفحتك index، أضف ملف page.js داخل دليل app:

ملف page.js الخاص
// `app/page.tsx` هو واجهة المستخدم لمسار `/`
export default function Page() {
  return <h1>مرحبًا، الصفحة الرئيسية!</h1>
}
// `app/page.js` هو واجهة المستخدم لمسار `/`
export default function Page() {
  return <h1>مرحبًا، الصفحة الرئيسية!</h1>
}

ثم، لإنشاء صفحات إضافية، أنشئ مجلدًا جديدًا وأضف ملف page.js بداخله. على سبيل المثال، لإنشاء صفحة لمسار /dashboard، أنشئ مجلدًا جديدًا باسم dashboard، وأضف ملف page.js بداخله:

// `app/dashboard/page.tsx` هو واجهة المستخدم لمسار `/dashboard`
export default function Page() {
  return <h1>مرحبًا، صفحة لوحة التحكم!</h1>
}
// `app/dashboard/page.js` هو واجهة المستخدم لمسار `/dashboard`
export default function Page() {
  return <h1>مرحبًا، صفحة لوحة التحكم!</h1>
}

جيد أن تعرف:

التخطيطات

التخطيط هو واجهة مستخدم مشتركة بين مسارات متعددة. عند التنقل، تحافظ التخطيطات على الحالة، تبقى تفاعلية، ولا تعيد التصيير. يمكن أيضًا تداخل التخطيطات.

يمكنك تعريف تخطيط عن طريق تصدير مكون React افتراضي من ملف layout.js. يجب أن يقبل المكون خاصية children التي سيتم ملؤها بتخطيط فرعي (إذا وجد) أو صفحة أثناء التصيير.

على سبيل المثال، سيكون التخطيط مشتركًا مع صفحات /dashboard و /dashboard/settings:

ملف layout.js الخاص
export default function DashboardLayout({
  children, // سيكون صفحة أو تخطيط متداخل
}: {
  children: React.ReactNode
}) {
  return (
    <section>
      {/* ضع واجهة المستخدم المشتركة هنا مثل رأس أو شريط جانبي */}
      <nav></nav>

      {children}
    </section>
  )
}
export default function DashboardLayout({
  children, // سيكون صفحة أو تخطيط متداخل
}) {
  return (
    <section>
      {/* ضع واجهة المستخدم المشتركة هنا مثل رأس أو شريط جانبي */}
      <nav></nav>

      {children}
    </section>
  )
}

التخطيط الجذري (مطلوب)

يتم تعريف التخطيط الجذري في المستوى الأعلى من دليل app وينطبق على جميع المسارات. هذا التخطيط مطلوب ويجب أن يحتوي على علامات html و body، مما يسمح لك بتعديل HTML الأولي المرسل من الخادم.

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>
        {/* واجهة مستخدم التخطيط */}
        <main>{children}</main>
      </body>
    </html>
  )
}
export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        {/* واجهة مستخدم التخطيط */}
        <main>{children}</main>
      </body>
    </html>
  )
}

تداخل التخطيطات

افتراضيًا، التخطيطات في تسلسل المجلدات متداخلة، مما يعني أنها تغلف التخطيطات الفرعية عبر خاصية children. يمكنك تداخل التخطيطات عن طريق إضافة layout.js داخل أجزاء مسار محددة (مجلدات).

على سبيل المثال، لإنشاء تخطيط لمسار /dashboard، أضف ملف layout.js جديد داخل مجلد dashboard:

تخطيط متداخل
export default function DashboardLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return <section>{children}</section>
}
export default function DashboardLayout({ children }) {
  return <section>{children}</section>
}

إذا كنت ستجمع بين التخطيطين أعلاه، فإن التخطيط الجذري (app/layout.js) سيغلف تخطيط لوحة التحكم (app/dashboard/layout.js)، والذي بدوره سيغلف أجزاء المسار داخل app/dashboard/*.

سيتم تداخل التخطيطين كما يلي:

تخطيطات متداخلة

جيد أن تعرف:

القوالب

القوالب مشابهة للتخطيطات من حيث أنها تغلف كل تخطيط فرعي أو صفحة. على عكس التخطيطات التي تستمر عبر المسارات وتحافظ على الحالة، تنشئ القوالب نسخة جديدة لكل من أطفالها عند التنقل. هذا يعني أنه عندما ينتقل المستخدم بين المسارات التي تشترك في قالب، يتم تحميل نسخة جديدة من المكون، يتم إعادة إنشاء عناصر DOM، لا يتم الحفاظ على الحالة، ويعاد مزامنة التأثيرات.

قد تكون هناك حالات تحتاج فيها إلى هذه السلوكيات المحددة، وتكون القوالب خيارًا أكثر ملاءمة من التخطيطات. على سبيل المثال:

  • الميزات التي تعتمد على useEffect (مثل تسجيل مشاهدات الصفحة) و useState (مثل نموذج تعليقات لكل صفحة).
  • لتغيير سلوك الإطار الافتراضي. على سبيل المثال، حدود Suspense داخل التخطيطات تظهر الحالة الاحتياطية فقط عند تحميل التخطيط لأول مرة وليس عند تبديل الصفحات. بالنسبة للقوالب، تظهر الحالة الاحتياطية في كل تنقل.

يمكن تعريف قالب عن طريق تصدير مكون React افتراضي من ملف template.js. يجب أن يقبل المكون خاصية children.

ملف template.js الخاص
export default function Template({ children }: { children: React.ReactNode }) {
  return <div>{children}</div>
}
export default function Template({ children }) {
  return <div>{children}</div>
}

من حيث التداخل، يتم تصيير template.js بين التخطيط وأطفاله. إليك نتيجة مبسطة:

Output
<Layout>
  {/* لاحظ أن القالب لديه مفتاح فريد. */}
  <Template key={routeParam}>{children}</Template>
</Layout>

البيانات الوصفية

في دليل app، يمكنك تعديل عناصر HTML <head> مثل title و meta باستخدام واجهات برمجة تطبيقات البيانات الوصفية (Metadata APIs).

يمكن تعريف البيانات الوصفية عن طريق تصدير كائن metadata أو دالة generateMetadata في ملف layout.js أو page.js.

import { Metadata } from 'next'

export const metadata: Metadata = {
  title: 'Next.js',
}

export default function Page() {
  return '...'
}
export const metadata = {
  title: 'Next.js',
}

export default function Page() {
  return '...'
}

جيد أن تعرف: يجب ألا تضيف يدويًا علامات <head> مثل <title> و <meta> إلى التخطيطات الجذرية. بدلاً من ذلك، يجب استخدام واجهة برمجة تطبيقات البيانات الوصفية (Metadata API) التي تتعامل تلقائيًا مع المتطلبات المتقدمة مثل البث وإزالة تكرار عناصر <head>.

تعرف على المزيد حول خيارات البيانات الوصفية المتاحة في مرجع API