تخطيطات الصفحة في 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>
من جديد عند تغيير الصفحة، ستُخزَّن حالته (مثل قيم الدخل input).
// 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 أن يَعرف أي العناصر قد تغيرت ليخزِّن الحالة.
ملاحظة: تُدعى هذه العملية بالمطابقة reconciliation، وهي الطريقة التي تعرف فيها React أية عناصر قد تغيّرت
مشاركة TypeScript
لا بد أن تنشئ نوعًا جديدًا لصفحاتك يتضمن الدالة getLayout
إن أردت استخدام TypeScript. ثم عليك أن تنشئ بعد ذلك نوعًا جديدًا لتطبيقك يلغي خاصيات المكوّن كي يستخدم النوع الذي أنشئ سابقًا.
// pages/index.tsx
import type { ReactElement } from 'react'
import Layout from '../components/layout'
import NestedLayout from '../components/nested-layout'
import type { NextPageWithLayout } from './_app'
const Page: NextPageWithLayout = () => {
return <p>hello world</p>
}
Page.getLayout = function getLayout(page: ReactElement) {
return (
<Layout>
<NestedLayout>{page}</NestedLayout>
</Layout>
)
}
export default Page
// pages/_app.tsx
import type { ReactElement, ReactNode } from 'react'
import type { NextPage } from 'next'
import type { AppProps } from 'next/app'
export 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 الرسمي.