تخطيطات الصفحة في Next.js

من موسوعة حسوب

يتيح لك نموذج React تفكيك الصفحة إلى سلسلة من المكوّنات التي يمكن الاستفادة من عدد منها في صفحات أخرى. فقد يكون للصفحات مثلًا شريط التنقل نفسه والتذييل نفسه.

// components/layout.js

import Navbar from './navbar'
import Footer from './footer'

export default function Layout({ children }) {
  return (
    <>
      <Navbar />
      <main>{children}</main>
      <Footer />
    </>
  )
}

أمثلة عن تخطيط الصفحات في Next.js

تخطيط مشترك واحد لتطبيق مخصص

إن كان لديك تخطيط واحد لكامل تطبيقك، بإمكانك إنشاء تطبيق مخصص Custom App وتغليفه بتخطيط واحد. ونظرًا لاستخدام المكوّن </ Layout> من جديد عند تغيير الصفحة، ستُخزَّن حالته (مثل قيم الدخل).

// pages/_app.js

import Layout from '../components/layout'

export default function MyApp({ Component, pageProps }) {
  return (
    <Layout>
      <Component {...pageProps} />
    </Layout>
  )
}

تخطيطات ما قبل الصفحة

بإمكانك إن احتجت إلى عدة تخطيطات إضافة الخاصية getLayout إلى صفحتك التي تعيد مكوّن React لتخطيط الصفحة. يسمح ذلك بتعريف تخطيط ما قبل الصفحة per-page، إذ يسمح إعادة دالة بالحصول على تخطيطات معقدة متداخلة إن أردنا ذلك.

// pages/index.js

import Layout from '../components/layout'
import NestedLayout from '../components/nested-layout'

export default function Page() {
  return {
    /** المحتوى الخاص بك */
  }
}

Page.getLayout = function getLayout(page) {
  return (
    <Layout>
      <NestedLayout>{page}</NestedLayout>
    </Layout>
  )
}
// pages/_app.js

export default function MyApp({ Component, pageProps }) {
  //استخدم التخطيط المعرّف على مستوى الصفحة إن كان متاحًا
  const getLayout = Component.getLayout || ((page) => page)

  return getLayout(<Component {...pageProps} />)
}

عند التنقل بين الصفحات لا بد أن تحافظ على حالة الصفحة (قيم الدخل، موقع شريط التمرير وغير ذلك) لضمان تجربة جيدة في التطبيقات وحيدة الصفحة Single-Page Application. يُمكِّن نمط التخطيط هذا من الحفاظ على الحالة لأن شجرة مكوّن React سيبقى كما هو عند التنقل بين الصفحات. إذ تتيح شجرة المكوِّن لتطبيق React أن يعرف أي العناصر قد تغيرت ليخزِّن الحالة.

ملاحظة: تُدعى هذه العملية بالمطابقة، وهي الطريقة التي تعرف فيها React أية عناصر قد تغيّرت

مشاركة TypeScript

لابد أن تنشئ نوعًا جديدًا لصفحاتك يتضمن الدالة getLayout إن أردت استخدام TypeScript. ثم عليك أن تنشئ بعد ذلك نوعًا جديدًا لتطبيقك يلغي خاصيات المكوّن كي يستخدم النوع الذي أنشئ سابقًا.

// pages/index.tsx

import type { ReactElement } from 'react'
import Layout from '../components/layout'
import NestedLayout from '../components/nested-layout'

export default function Page() {
  return {
    /** المحتوى */
  }
}

Page.getLayout = function getLayout(page: ReactElement) {
  return (
    <Layout>
      <NestedLayout>{page}</NestedLayout>
    </Layout>
  )
}
// pages/_app.tsx

import type { ReactElement, ReactNode } from 'react'
import type { NextPage } from 'next'
import type { AppProps } from 'next/app'

type NextPageWithLayout = NextPage & {
  getLayout?: (page: ReactElement) => ReactNode
}

type AppPropsWithLayout = AppProps & {
  Component: NextPageWithLayout
}

export default function MyApp({ Component, pageProps }: AppPropsWithLayout) {
  //استخدم التخطيط المعرّف على مستوى الصفحة إن كان متاحًا
  const getLayout = Component.getLayout ?? ((page) => page)
  return getLayout(<Component {...pageProps} />)
}

إحضار البيانات

يمكنك إحضار البيانات من جانب العميل إلى التخطيط باستخدام الخطاف useEffect أو المكتبة SWR. لا يمكنك استخدام الدالتين getStaticProps أو getServerSideProps حاليًا لأن هذا الملف ليس صفحة.

// components/layout.js

import useSWR from 'swr'
import Navbar from './navbar'
import Footer from './footer'

export default function Layout({ children }) {
  const { data, error } = useSWR('/api/navigation', fetcher)

  if (error) return <div>Failed to load</div>
  if (!data) return <div>Loading...</div>

  return (
    <>
      <Navbar links={data.links} />
      <main>{children}</main>
      <Footer />
    </>
  )
}

المصادر

  • صفحة Layouts في توثيق Next.js الرسمي