الفرق بين المراجعتين لصفحة: «Next.js/api data fetching»
لا ملخص تعديل |
جميل-بيلوني (نقاش | مساهمات) طلا ملخص تعديل |
||
(3 مراجعات متوسطة بواسطة مستخدمين اثنين آخرين غير معروضة) | |||
سطر 3: | سطر 3: | ||
== الدالة غير المتزامنة <code>getInitialProps</code> == | == الدالة غير المتزامنة <code>getInitialProps</code> == | ||
''' | '''ملاحظة:''' قدّمت النسخة 13 من Next.js مجلدًا جديدًا يُدعى <code>app/</code>. ويدعم هذا المجلد إحضار البيانات من نفس المكان على صعيد المكوًنات باستخدام خطاف React الجديد <code>use</code> وواجهة الويب البرمجية الموّسعة <code>fetch</code> | ||
تُمكّنك الدالة <code>getInitialProps</code> من تصيير المحتوى من جانب الخادم في [[Next.js/pages|الصفحة]]، وتسمح لك بنقل البيانات بشكل أولي، أي إرسال الصفحة بالبيانات التي أنتجها الخادم، وهذا مفيد خصوصًا في تحسين محركات البحث SEO. | |||
'''ملاحظة''': يُعطل استخدام الدالة <code>getInitialProps</code> [[Next.js/automatic static optimization|التحسين التلقائي الساكن]]. | '''ملاحظة''': يُعطل استخدام الدالة <code>getInitialProps</code> [[Next.js/automatic static optimization|التحسين التلقائي الساكن]]. | ||
سطر 197: | سطر 197: | ||
function Page({ data }: InferGetServerSidePropsType<typeof getServerSideProps>) { | function Page({ data }: InferGetServerSidePropsType<typeof getServerSideProps>) { | ||
// سيحلل المنشورات وفق نوع البيانات | // سيحلل المنشورات وفق نوع البيانات | ||
} | |||
export default Page | |||
</syntaxhighlight>ستعمل الأنواع الضمنية أيضًا مع الدالة <code>GetServerSideProps</code>:<syntaxhighlight lang="javascript"> | |||
import { InferGetServerSidePropsType } from 'next' | |||
type Data = { ... } | |||
export const getServerSideProps = async () => { | |||
const res = await fetch('https://.../data') | |||
const data: Data = await res.json() | |||
return { | |||
props: { | |||
data, | |||
}, | |||
} | |||
} | |||
function Page({ data }: InferGetServerSidePropsType<typeof getServerSideProps>) { | |||
// سيحلل البيانات إلى النوع المطلوب | |||
} | } | ||
سطر 288: | سطر 309: | ||
* تصيَّر المسارات المعادة من قبل الدالة <code>getStaticProps</code> إلى <code>HTML</code> أثناء البناء بواسطة الدالة <code>getStaticProps</code>. | * تصيَّر المسارات المعادة من قبل الدالة <code>getStaticProps</code> إلى <code>HTML</code> أثناء البناء بواسطة الدالة <code>getStaticProps</code>. | ||
* لن ينتج عن المسارات التي لم توّلد أثناء البناء صفحات 404، بل ستقدّم نسخة تراجع عن الصفحة عند أول طلب إلى مسار كهذا. لن تُخدّم زواحف ويب Web crawler (مثل زواحف Google) بنسخة تراجع، وسيسلك المسار سلوك الحالة <code>'fallback: 'blocking</code> التي سنراها تاليًا. | * لن ينتج عن المسارات التي لم توّلد أثناء البناء صفحات 404، بل ستقدّم نسخة تراجع عن الصفحة عند أول طلب إلى مسار كهذا. لن تُخدّم زواحف ويب Web crawler (مثل زواحف Google) بنسخة تراجع، وسيسلك المسار سلوك الحالة <code>'fallback: 'blocking</code> التي سنراها تاليًا. | ||
* عندما ننتقل إلى صفحة فيها <code>fallback: true</code> من خلال الكائنين <code>next/link</code> أو <code>next/router</code>، فلن تُخدّم Next.js الطلب بصفحة تراجع بل ستسلك الصفح سلوك الحالة <code>fallback: 'blocking'</code>. | |||
* توّلد Next.js في الخلفية وبشكل ساكن بيانات <code>HTML</code> و <code>JSON</code> للمسار المطلوب، ويتضمن ذلك تنفيذ الدالة <code>getStaticProps</code>. | * توّلد Next.js في الخلفية وبشكل ساكن بيانات <code>HTML</code> و <code>JSON</code> للمسار المطلوب، ويتضمن ذلك تنفيذ الدالة <code>getStaticProps</code>. | ||
* عندما تكتمل العملية، يتلقى المتصفح بيانات <code>JSON</code> للمسار المولّد والتي تُستخدم في التصيير التلقائي للصفحة بالخاصيات المطلوبة. ومن وجهة نظر المستخدم، ستتبدل الصفحة من صفحة تراجع إلى صفحة كاملة. | * عندما تكتمل العملية، يتلقى المتصفح بيانات <code>JSON</code> للمسار المولّد والتي تُستخدم في التصيير التلقائي للصفحة بالخاصيات المطلوبة. ومن وجهة نظر المستخدم، ستتبدل الصفحة من صفحة تراجع إلى صفحة كاملة. | ||
سطر 548: | سطر 570: | ||
function Blog({ posts }: InferGetStaticPropsType<typeof getStaticProps>) { | function Blog({ posts }: InferGetStaticPropsType<typeof getStaticProps>) { | ||
// Post[] سيحلل البيانات وفق النوع | // Post[] سيحلل البيانات وفق النوع | ||
} | |||
export default Blog | |||
</syntaxhighlight>ستعمل الأنواع الضمنية أيضًا مع الدالة <code>GetStaticProps</code>:<syntaxhighlight lang="javascript"> | |||
import { InferGetStaticPropsType } from 'next' | |||
type Post = { | |||
author: string | |||
content: string | |||
} | |||
export const getStaticProps = async () => { | |||
const res = await fetch('https://.../posts') | |||
const posts: Post[] = await res.json() | |||
return { | |||
props: { | |||
posts, | |||
}, | |||
} | |||
} | |||
function Blog({ posts }: InferGetStaticPropsType<typeof getStaticProps>) { | |||
//post[] سيحلل المنشورات إلى النوع | |||
} | } | ||
سطر 556: | سطر 602: | ||
* الصفحات [https://nextjs.org/docs/api-reference/data-fetching/get-initial-props Data fetching] من توثيق Next.js الرسمي. | * الصفحات [https://nextjs.org/docs/api-reference/data-fetching/get-initial-props Data fetching] من توثيق Next.js الرسمي. | ||
[[تصنيف:Next.js|{{SUBPAGENAME}}]] | |||
[[تصنيف:Next.js API|{{SUBPAGENAME}}]] |
المراجعة الحالية بتاريخ 16:41، 4 فبراير 2023
نستعرض في هذه الصفحة من التوثيق الدوال التي تستخدمها Next.js في إحضار البيانات.
الدالة غير المتزامنة getInitialProps
ملاحظة: قدّمت النسخة 13 من Next.js مجلدًا جديدًا يُدعى app/
. ويدعم هذا المجلد إحضار البيانات من نفس المكان على صعيد المكوًنات باستخدام خطاف React الجديد use
وواجهة الويب البرمجية الموّسعة fetch
تُمكّنك الدالة getInitialProps
من تصيير المحتوى من جانب الخادم في الصفحة، وتسمح لك بنقل البيانات بشكل أولي، أي إرسال الصفحة بالبيانات التي أنتجها الخادم، وهذا مفيد خصوصًا في تحسين محركات البحث SEO.
ملاحظة: يُعطل استخدام الدالة getInitialProps
التحسين التلقائي الساكن.
تُعد الدالة getInitialProps
دالة غير متزامنة async
يمكن إضافتها إلى أي صفحة كتابع ساكن static method
. إليك مثالًا:
function Page({ stars }) {
return <div>Next stars: {stars}</div>
}
Page.getInitialProps = async (ctx) => {
const res = await fetch('https://api.github.com/repos/vercel/next.js')
const json = await res.json()
return { stars: json.stargazers_count }
}
export default Page
أو باستخدام مكوّن صنف:
import React from 'react'
class Page extends React.Component {
static async getInitialProps(ctx) {
const res = await fetch('https://api.github.com/repos/vercel/next.js')
const json = await res.json()
return { stars: json.stargazers_count }
}
render() {
return <div>Next stars: {this.props.stars}</div>
}
}
export default Page
تُستخدم الدالة getInitialProps
لإحضار بعض البيانات بشكل غير متزامن لتُحلَّل بعدها البيانات الجاهزة المعادة props
من الدالة أثناء التصيير في الواجهة الخلفية بشكل مشابه لما يفعله التابع JSON.stringify
. تأكد أن الكائن الذي تعيده الدالة getInitialProps
هو كائن بسيط لا يحتوي على الخاصيات Date
أو Map
أو Set
.
تنفذ الدالة getInitialProps
على الخادم فقط لتحميل الصفحة مبدئيًا، ثم تُنفَّذ في الواجهة الأمامية عند الانتقال إلى وجهة أخرى باستخدام المكون next/link
أو المكون next/router
. لكن إن استخدمت الدالة getInitialProps
تطبيقًا مخصصًا app.js_
وتضمنت الصفحة الهدف الدالة getServerSideProps
عندها لن تعمل الدالة getInitialProps
على الخادم.
الكائن context
تتلقى الدالة getInitialProps
وسيطًا واحدًا يدعى context
، وهو كائن يمتلك الخاصيات التالية:
pathname
: الوجهة الحالية، وهي مسار الصفحة ضمن المجلدpages/
.query
: قسم الاستعلام النصي من عنوان URL والمُحلَّل ككائن.asPath
: من النوعString
، ويمثل المسار الفعلي (بما في ذلك الاستعلام) الظاهر في شريط عنوان المتصفح.req
: كائن طلب HTTP (خادم فقط).res
: كائن استجابة HTTP (خادم فقط).err
: كائن خطأ وينتج عن أي خطا يحدث أثناء التصيير.
التحفظات على استخدام الدالة
- لا يمكن استخدام الدالة
getInitialProps
داخل المكوّنات الأبناء، بل فقط ضمن التصدير الافتراضي لكل صفحة. - إن كنت تستخدم وحدات الواجهة الخلفية فقط داخل الدالة
getInitialProps
، فتأكد من إدراجها بشكل صحيح وإلا ستبطئ تطبيقك.
ملاحظة: بغض النظر عن نوع التصيير ستُمرَّر أية خاصية
props
إلى مكون الصفحة وتُستعرض في الواجهة الأمامية كجزء من صفحة HTML المبدئية. إن الغاية من ذلك هو السماح بترطيب الصفحة hydrate بالشكل الصحيح. تأكد من عدم تمرير أية معلومات حساسة لا ينبغي عرضها في الواجهة الأمامية من خلال الخاصياتprops
.
استخدام الدالة مع TypeScript
إن كنت تستخدم TypeScript، بإمكانك استخدام النوع NextPage
من أجل مكوِّنات الدوال:
import { NextPage } from 'next'
interface Props {
userAgent?: string;
}
const Page: NextPage<Props> = ({ userAgent }) => (
<main>Your user agent: {userAgent}</main>
)
Page.getInitialProps = async ({ req }) => {
const userAgent = req ? req.headers['user-agent'] : navigator.userAgent
return { userAgent }
}
export default Page
ويمكنك استخدام NextPageContext
من أجل React.Component
:
import React from 'react'
import { NextPageContext } from 'next'
interface Props {
userAgent?: string;
}
export default class Page extends React.Component<Props> {
static async getInitialProps({ req }: NextPageContext) {
const userAgent = req ? req.headers['user-agent'] : navigator.userAgent
return { userAgent }
}
render() {
const { userAgent } = this.props
return <main>Your user agent: {userAgent}</main>
}
}
الدالة غير المتزامنة getServerSideProps
عندما تُصدِّر الصفحة دالة تُدعى getServerSideProps
(تصيير من جانب الخادم)، تُصيَّر هذه الصفحة مسبقًا عند كل طلب باستخدام البيانات المعادة من هذه الدالة. ولهذا الأمر فائدته إن كنت تريد إحضار البيانات التي تتغير أحيانًا، وتحديث الصفحة لعرض آخر حالة للبيانات:
export async function getServerSideProps(context) {
return {
props: {}, // تُمرر إلى مكون الصفحة على شكل خاصيات
}
}
بإمكانك إدراج الوحدات البرمجية في أعلى مستوى كي تستخدمها مع getServerSideProps
، ولن تُجمّع هذه الوحدات ضمن شيفرة جانب العميل (الواجهة الأمامية). أي بإمكانك كتابة الشيفرة التي تُنفّذ على الخادم مباشرة ضمن getServerSideProps
بما في ذلك إحضار البيانات من قاعدة بيانات.
الكائن context
تتلقى الدالة getServerSideProps
معاملًا واحدًا يدعى context
، وهو كائن يمتلك المفاتيح التالية:
params
: إن استخدمت الصفحة مسارات ديناميكية، سيضم هذا المفتاح معاملات الوجهة. إذ تبدو هذه المعاملات على الشكل{ ...:id}
إن كان اسم الصفحة مثلًا[id].js
query
: قسم الاستعلام النصي من عنوان URL والمُحلَّل ككائن.req
: كائن الرسائل الواردة في HTTP مع الخاصية الإضافيةcookies
، وهي كائن له مفاتيح نصية ترتبط مع القيم النصية لملفات تعريف الارتباط.res
: كائن استجابة HTTP (خادم فقط).preview
: يأخذ القيمةtrue
عندما تكون الصفحة في وضع الاستعراض.previewData
: بيانات الاستعراض التي تضبطهاsetPreviewData
.resolvedUrl
: نسخة عادية من عنوانURL
المطلوب بعد تجريده من بادئةnext/data_
وذلك للتنقل في طرف العميل، وتتضمن قيم الاستعلام الأصلي.locale
: يضم الإعداد المحلي الفعّال (إن مُكِّن).locales
: يضم كل الإعدادات المحلية المدعومة (إن مُكِّن).defaultLocale
: يضم كل الإعدادات المحلية الافتراضية المهيأة (إن مُكِّن).
القيم التي تعيدها الدالة getServerSideProps
لا بد أن تعيد هذه الدالة كائنًا له إحدى الخاصيات التالية:
الخاصية props
وهو كائن من الشكل (مفتاح-قيمة) يتلقى كل قيمه من مكوّن الصفحة. ينبغي أن يكون الكائن قابلًا للتحليل كي تُحلل الخاصيات الممررة باستخدام التابع JSON.stringify
.
export async function getServerSideProps(context) {
return {
props: { message: `Next.js is awesome` }, // تمرر إلى مكون الصفحة كخاصيات
}
}
الخاصية notFound
وهي قيمة منطقية تتيح للصفحة أن تعيد رمز الحالة 404 وصفحة هذه الحالة. تُعيد الصفحة عندما تكون قيمة هذه الخاصية true
رمز الحالة 404
حتى لو وُلِّدت بنجاح سابقًا. إن الغاية من ذلك دعم بعض حالات الاستخدام مثل المحتوى الذي يولّده مستخدم ثم يُزيله.
export async function getServerSideProps(context) {
const res = await fetch(`https://.../data`)
const data = await res.json()
if (!data) {
return {
notFound: true,
}
}
return {
props: { data }, // يُمرر إلى مكوّن الصفحة كخاصيات
}
}
الخاصية redirect
يتيح الكائن redirect
إعادة التوجيه إلى مصادر داخلية أو خارجية، وينبغي أن يطابق الشكل { destination: string, permanent: boolean }
. قد تحتاج في حالات نادرة تعيين رموز حالة مخصصة لعملاء HTTP
الأقدم كي يُعاد توجيههم بالشكل الصحيح. في حالات كهذه، استخدم الخاصية statusCode
بدلًا من permanent
لكن لا تستخدمهما معًا:
export async function getServerSideProps(context) {
const res = await fetch(`https://.../data`)
const data = await res.json()
if (!data) {
return {
redirect: {
destination: '/',
permanent: false,
},
}
}
return {
props: {}, //يُمرر إلى مكوّن الصفحة كخاصيات
}
}
استخدام الدالة مع TypeScript
بإمكانك استخدام النوع GetServerSideProps
من المكتبة next
:
import { GetServerSideProps } from 'next'
export const getServerSideProps: GetServerSideProps = async (context) => {
// ...
}
وإن كنت تريد استخدام الأنواع الاستدلالية inferred typings للخاصيات، بإمكانك استخدام <InferGetServerSidePropsType<typeof getServerSideProps
:
import { InferGetServerSidePropsType } from 'next'
type Data = { ... }
export const getServerSideProps = async () => {
const res = await fetch('https://.../data')
const data: Data = await res.json()
return {
props: {
data,
},
}
}
function Page({ data }: InferGetServerSidePropsType<typeof getServerSideProps>) {
// سيحلل المنشورات وفق نوع البيانات
}
export default Page
ستعمل الأنواع الضمنية أيضًا مع الدالة GetServerSideProps
:
import { InferGetServerSidePropsType } from 'next'
type Data = { ... }
export const getServerSideProps = async () => {
const res = await fetch('https://.../data')
const data: Data = await res.json()
return {
props: {
data,
},
}
}
function Page({ data }: InferGetServerSidePropsType<typeof getServerSideProps>) {
// سيحلل البيانات إلى النوع المطلوب
}
export default Page
الدالة غير المتزامنة getStaticPaths
عندما تُصدِّر الصفحة دالة تُدعى getStaticPaths
من صفحة تستخدم مسارات ديناميكية، تُصيِّر هذه الصفحة مسبقًا وبشكل ساكن كل المسارات التي تحددها الدالة.
export async function getStaticPaths() {
return {
paths: [
{ params: { ... } } //في الأسفل "pathes" اطلع على القسم
],
fallback: true, false or "blocking" // في الأسفل "fallback" اطلع على
};
}
القيم التي تعيدها الدالة getStaticPaths
لا بد أن تعيد هذه الدالة كائنًا له الخاصيات المطلوبة التالية:
الخاصية path
وهي مفتاح يحدد المسارات التي تُصيّر مسبقًا. فلو افترضنا مثلًا وجود صفحة تستخدم وجهات ديناميكية على النحو pages/posts/[id].js
. فلو صَدّّرت عندها الدالة getStaticPaths
من الصفحة وأعدت المسارات paths
كالتالي:
return {
paths: [
{ params: { id: '1' }},
{
params: { id: '2' },
// with i18n configured the locale for the path can be returned as well
locale: "en",
},
],
fallback: ...
}
ستوّلد Next.js بشكل ساكن الصفحات posts/1/
و posts/2/
أثناء تنفيذ الأمر next build
باستخدام مكوّن الصفحة في pages/posts/[id].js
.
لا بد من تطابق قيمة كل كائن params
مع المعاملات المستخدمة في تسمية الصفحة:
- إن كان اسم الصفحة
pages/posts/[postId]/[commentId]
، ينبغي أن يتضمن عندها الكائنparams
الخاصيتينpostId
وcommentId
. - إن استخدمت تقنية التقاط كل الوجهات في تسمية الصفحة مثل
pages/[...slug]
، لا بد أن يتضمن عندها الكائنparams
المصفوفةslug
. فلو كانت هذه المصفوفة مثلًا['hello', 'world']
، ستوّلد Next.js بشكل ساكن الصفحة التي عنوانهاhello/world/
- إن استخدمت الصفحة تقنية التقاط جميع الوجهات اختياريًا، استخدم
null
أو[]
أوundefined
أوfalse
لتصيير الوجهة الأكثر قربًا من جذر التطبيق. فلو استخدمتslug: false
للصفحاتpages/[[...slug]]
، ستولَّد الصفحة في جذر التطبيق/
.
إن المعامل params
حساس لحالة الأحرف ومن الأفضل كتابته بأحرف صغيرة للتأكد من توليد المسارات بالشكل الصحيح. فلو أعيدت الكلمة WoRLD
إلى معامل ما، ستطابق الحالة التي يكون فيها المسار الفعلي هو WoRLD
وليس world
أو World
.
وبمعزل عن الكائن params
، يمكن إعادة حقل الإعداد المحلي locale
عندما يُهيأ التوجه i18n الذي يضبط بدوره الإعداد المحلي للمسار الذي يُولَّد.
الخاصية fallback: false
إن كانت قيمة الخاصية fallback
هي false
فستكون الصفحة 404 هي نتيجة كل مسار لا تعيده الدالة getStaticPaths
. عندما تُنفِّذ الأمر next build
، تكتشف Next.js إن أعادت الدالة getStaticPaths
القيمة fallback: false
، كي توّلد عندها المسارات التي تعيدها الدالة getStaticPaths
فقط.
تظهر فائدة الأمر إن كان لديك عدد محدود من المسارات التي عليك إنشاؤها، أو في الحالة التي لن تضيف فيها بيانات جديدة للصفحة غالبًا. لكن إن رأيت أنك تحتاج إلى مسارات أكثر وكان fallback: false
، لا بد عندها من تنفيذ الأمر next build
مجددًا لكي تولَّد المسارات الجديدة.
يصيّر المثال التالي منشورًا واحدًا في الصفحة يُدعى pages/posts/[id].js
. إذ تُجلب قائمة منشورات المدونة من منظومة إدارة محتوى CMS وتُعاد من قبل الدالة getStaticPaths
. عندها ستحضر هذه الدالة ولكل صفحة بيانات المنشور من منظومة إدارة المحتوى باستخدام الدالة getStaticProps
:
// pages/posts/[id].js
function Post({ post }) {
// تصيير المنشور...
}
// تُستدعى هذه الدالة أثناء البناء
export async function getStaticPaths() {
//خارجية للحصول على المنشورات API استدعي وصلة
const res = await fetch('https://.../posts')
const posts = await res.json()
// الحصول على المسارات التي تريد تصييرها مسبقًا وفقًل للمنشورات
const paths = posts.map((post) => ({
params: { id: post.id },
}))
// سنصيّر مسبقًا هذه المسارات فقط أثناء البناء
// { fallback: false } تعيد بقية المسارات الصفحة 404 لأن
return { paths, fallback: false }
}
// تُستدعى أيضًا أثناء البناء
export async function getStaticProps({ params }) {
//للمنشور id المعرف params يتضمن
// 1 هو params.id سيكون /posts/1 في حال
const res = await fetch(`https://.../posts/${params.id}`)
const post = await res.json()
// تمرير بيانات المنشور إلى الصفحة كخاصيات
return { props: { post } }
}
export default Post
الخاصية fallback: true
إن كانت قيمة fallback
هي true
سيتغير سلوك الدالة getStaticProps
على النحو التالي:
- تصيَّر المسارات المعادة من قبل الدالة
getStaticProps
إلىHTML
أثناء البناء بواسطة الدالةgetStaticProps
. - لن ينتج عن المسارات التي لم توّلد أثناء البناء صفحات 404، بل ستقدّم نسخة تراجع عن الصفحة عند أول طلب إلى مسار كهذا. لن تُخدّم زواحف ويب Web crawler (مثل زواحف Google) بنسخة تراجع، وسيسلك المسار سلوك الحالة
'fallback: 'blocking
التي سنراها تاليًا. - عندما ننتقل إلى صفحة فيها
fallback: true
من خلال الكائنينnext/link
أوnext/router
، فلن تُخدّم Next.js الطلب بصفحة تراجع بل ستسلك الصفح سلوك الحالةfallback: 'blocking'
. - توّلد Next.js في الخلفية وبشكل ساكن بيانات
HTML
وJSON
للمسار المطلوب، ويتضمن ذلك تنفيذ الدالةgetStaticProps
. - عندما تكتمل العملية، يتلقى المتصفح بيانات
JSON
للمسار المولّد والتي تُستخدم في التصيير التلقائي للصفحة بالخاصيات المطلوبة. ومن وجهة نظر المستخدم، ستتبدل الصفحة من صفحة تراجع إلى صفحة كاملة.
- في الوقت ذاته، تضيف Next.js هذا المسار إلى الصفحات التي تصيَّر مسبقًا، وتُخدَّّم الطلبات اللاحقة لهذا المسار من الصفحة التي ولِّدت كغيرها من الصفحات التي تُصيّر مسبقًا أثناء البناء.
ملاحظة: لا يمكن استخدام
fallback: true
معnext export
.
متى تستفيد من الخاصية fallback: true
تظهر فائدة fallback: true
عندما يضم التطبيق عددًا كبيرًا من الصفحات الساكنة التي تعتمد على البيانات. فلو أردت تصيير جميع الصفحات في التطبيق ستسغرق عملية البناء وقتًا طويلًا جدًا.
بدلًا من ذلك، بإمكانك توليد مجموعة صغيرة من الصفحات واستخدام fallback: true
للبقية. فعندما يطلب أحدهم صفحة لم تولّد بعد، سيرى هذه الصفحة وهي تحمل مؤشر التحميل أو مكوّن هيكل الصفحة. وبعد فترة وجيزة، ينتهي تنفيذ getStaticProps
وتصُيّر الصفحة بالبيانات المطلوبة. بعد ذلك سيحصل كل من يطلب هذه الصفحة على هذه النسخة المصيّرة مسبقًا، مما يضمن تجربة سريعة للمستخدم مع المحافظة على سرعة البناء ومزايا التوليد الساكن.
لا تُحدِّث fallback: true
الصفحات المولّدة، لهذا ننصحك بإلقاء نظرة على التجديد التدريجي الساكن.
الخاصية 'fallback: 'blocking
إن كانت قيمة fallback
هي 'blocking'
، تنتظر المسارات الجديدة التي لم تعيدها الدالة getStaticPaths
حتى تولَّد صفحات HTML
كما هو الحال عند التصيير في جانب الخادم، ثم تُخزّن مؤقتًا للطلبات اللاحقة أي أنها تُصيَّر مرة لكل مسار.
تسلك الدالة getStaticProps
السلوك التالي:
- تُصيَّر المسارات التي تعيدها
getStaticPaths
إلى صفحاتHTML
أثناء البناء بواسطة الدالةgetStaticProps
. - لن ينتج عن المسارات التي لم تولَّد أثناء البناء صفحات 404، بل تصييرها Next.js في جانب الخادم عند أول طلب وتعيد صفحة
HTML
الناتجة.
- عندما تكتمل العملية، يتلقى المتصفح بيانات
HTML
للمسار المولّد. ومن وجهة نظر المستخدم، ستتبدل الحالة من "المتصفح يطلب الصفحة" إلى "تحميل الصفحة بالكامل"، ولن تكون هناك حالة تحميل أو تراجع. - في الوقت ذاته، تضيف Next.js هذا المسار إلى الصفحات التي تصيَّر مسبقًا، وتُخدَّّم الطلبات اللاحقة لهذا المسار من الصفحة التي ولِّدت كغيرها من الصفحات التي تُصيّر مسبقًا أثناء البناء.
لا تُحدّث 'fallback: 'blocking
الصفحات المولّدة، لهذا عليك استخدام التجديد التدريجي الساكن على التوازي معها.
ملاحظة: لا يمكن استخدام
'fallback: 'blocking
معnext export
.
صفحات التراجع Fallback
في نسخة التراجع fallback من الصفحة:
- ستكون خاصيات الصفحة فارغة.
- باستخدام الموّجه، يمكنك التحقق من تصيير صفحة التراجع، إذ ستكون قيمة
router.isFallback
هيtrue
.
يعرض المثال التالي حالات عن استخدام isFallback
:
// pages/posts/[id].js
import { useRouter } from 'next/router'
function Post({ post }) {
const router = useRouter()
// إن لم تولّد الصفحة بعدن سيُعرض التالي بشكل مبدئي حتى ينتهي تنفيذ الدالة
// getStaticProps()
if (router.isFallback) {
return <div>Loading...</div>
}
// تصيير المنشور...
}
// تُستدعى هذه الدالة أثناء البناء
export async function getStaticPaths() {
return {
//أثناء البناء `/posts/1` و `/posts/2` يُولّد فقط
paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
// تمكين التوليد الستاتيكي لصفحات إضافية
// مثلًا `/posts/3`
fallback: true,
}
}
// يُستدعى هذا أيضًا أثناء البناء
export async function getStaticProps({ params }) {
//للمنشور id المعرف params يتضمن
// 1 هو params.id سيكون /posts/1 في حال
const res = await fetch(`https://.../posts/${params.id}`)
const post = await res.json()
// تمرير بيانات المنشورات إلى الصفحة عبر الخاصيات
return {
props: { post },
// تجديد المنشور على الأكثر مرة كل ثانية
revalidate: 1,
}
}
export default Post
استخدام getStaticPaths
مع TypeScript
بإمكانك استخدام النوع GetStaticPaths
من المكتبة next
:
import { GetStaticPaths } from 'next'
export const getStaticPaths: GetStaticPaths = async () => {
// ...
}
الدالة غير المتزامنة getStaticProps
يؤدي تصدير دالة تُدعى getStaticProps
إلى التصيير المسبق للصفحة أثناء البناء باستخدام الخاصيات التي تُعيدها الدالة.
export async function getStaticProps(context) {
return {
props: {}, //تُمرر إلى الصفحة على شكل خاصيات
}
}
بإمكانك إدراج الوحدات البرمجية في أعلى مستوى كي تستخدمها مع getStaticProps
، ولن تُجمّع هذه الوحدات ضمن شيفرة جانب العميل (الواجهة الأمامية). أي بإمكانك كتابة الشيفرة التي تُنفّذ على الخادم مباشرة ضمن getStaticProps
بما في ذلك إحضار البيانات من قاعدة بيانات.
الكائن context
تتلقى الدالة getStaticProps
معاملًا واحدًا يدعى context
، وهو كائن يمتلك المفاتيح التالية:
params
: إن استخدمت الصفحة مسارات ديناميكية، سيضم هذا المفتاح معاملات الوجهة. إذ تبدو هذه المعاملات على الشكل{ ...:id}
إن كان اسم الصفحة مثلًا[id]
. ينبغي أن تستخدم هذه المعاملات معgetStaticPaths
، وهذا ما سنشرحه لاحقًا.preview
: يأخذ القيمةtrue
عندما تكون الصفحة في وضع الاستعراض.previewData
: بيانات الاستعراض التي تضبطهاsetPreviewData
.locale
: يضم الإعداد المحلي الفعّال (إن مُكِّن).locales
: يضم كل الإعدادات المحلية المدعومة (إن مُكِّن).defaultLocale
: يضم كل الإعدادات المحلية الافتراضية المهيأة (إن مُكِّن).
القيم التي تعيدها الدالة getStaticProps
لا بد أن تعيد هذه الدالة كائنًا له إحدى الخاصيات التالية props
أو redirect
أو notFound
متبوعة بالخاصية الاختيارية revalidate
.
الخاصية props
وهو كائن من الشكل (مفتاح-قيمة) يتلقى قيمه من مكوّن الصفحة. ينبغي أن يكون الكائن قابلًا للتحليل كي تُحلل الخاصيات الممررة باستخدام التابع JSON.stringify
.
export async function getStaticProps(context) {
return {
props: { message: `Next.js is awesome` }, // تمرر إلى مكون الصفحة كخاصيات
}
}
الخاصية revalidate
وتمثّل عدد الثواني التي يمكن أن يحدث بعدها تجديد للصفحة (تأخذ القيمة false
افتراضيًا، أي لا إعادة تحقق):
// تُستدعى هذه الدالة أثناء البناء من جانب الخادم
// يمكن أن تُستدعى مجددًا من قبل دالة لا تُنفَّذ على الخادم
// مفعّلة revalidate إن كانت إعادةالخاصية
export async function getStaticProps()
const res = await fetch('https://.../posts')
const posts = await res.json()
return {
props: {
posts,
},
//إعادة تجديد الصفحة Next.js تحاول
// Next.js will attempt to re-generate the page:
// عندما يرد طلب
// وغالبًا بعد 10 ثوانٍ
revalidate: 10, // بالثواني
}
}
إن دعمت الصفحة التجديد الساكن التدريجي ISR، يمكن تحديد حالة التخزين المؤقت بقراءة قيمة ترويسة الاستجابة x-nextjs-cache
والتي قد تكون:
MISS
: المسار غير موجود في الذاكرة المؤقتة (يحدث ذلك غالبًا مرة واحدة عند أول زيارة).STALE
: المسار موجود في الذاكرة المؤقتة لكنه تجاوز فترة الصلاحية لذا سيُحدّث في الخلفية.HIT
: المسار في الذاكرة المؤقتة وضمن فترة الصلاحية.
الخاصية notFound
وهي قيمة منطقية تتيح للصفحة أن تعيد رمز الحالة 404 وصفحة هذه الحالة. تُعيد الصفحة عندما تكون قيمة هذه الخاصية true
رمز الحالة 404
حتى لو وُلِّدت الصفحة بنجاح سابقًا. إن الغاية من ذلك دعم بعض حالات الاستخدام مثل المحتوى الذي يولّده مستخدم ويُزال من قبله. تسلك الخاصية notFound
نفسك سلوك الخاصية السابقة revalidate
:
export async function getServerSideProps(context) {
const res = await fetch(`https://.../data`)
const data = await res.json()
if (!data) {
return {
notFound: true,
}
}
return {
props: { data }, // يُمرر إلى مكوّن الصفحة كخاصيات
}
}
ملاحظة: لا حاجة لاستخدام
notFound
مع نمط التراجعfallback: false
لأن المسارات التي تعيدها الدالةgetStaticPaths
هي التي تُصيّر مسبقًا فقط.
الخاصية redirect
يتيح الكائن redirect
إعادة التوجيه إلى مصادر داخلية أو خارجية، وينبغي أن يطابق الشكل { destination: string, permanent: boolean }
. قد تحتاج في حالات نادرة تعيين رموز حالة مخصصة لعملاء HTTP
الأقدم كي يُعاد توجيههم بالشكل الصحيح. في حالات كهذه، استخدم الخاصية statusCode
بدلًا من permanent
لكن لا تستخدمهما معًا. بإمكانك أيضًا ضبط basePath: false
بشكل مشابه لإعادة التوجيه من خلال الملف next.config.js
:
export async function getStaticProps(context) {
const res = await fetch(`https://...`)
const data = await res.json()
if (!data) {
return {
redirect: {
destination: '/',
permanent: false,
//رمز الحالة : 301
},
}
}
return {
props: { data }, //تمرر إلى مكوّن الصفحة كخاصيات
}
}
إن كانت عمليات إعادة التوجيه معروفة أثناء بناء التطبيق، فلا بد من إضافتها إلى الملف next.config.js
بدلًا من ذلك.
قراءة الملفات باستخدام ()process.cwd
:
بإمكانك قراءة الملفات مباشرة من منظومة الملفات في getStaticProps
، لكن عليك أن تحصل على المسار الكامل لهذا الملف. ولن تستطيع استخدام التعليمة dirname__
لأنها ستعيد مسارًا يختلف عن مسار المجلد، لأن Next.js تُصرّف الشيفرة في مجلدات مختلفة. استخدم بدلًا من ذلك التابع ()process.cwd
الذي يعيد المجلد الذي تُنفَّذ فيه Next.js:
import { promises as fs } from 'fs'
import path from 'path'
// getStaticProps() ستجهز المنشورات في زمن البناء عن طريق
function Blog({ posts }) {
return (
<ul>
{posts.map((post) => (
<li>
<h3>{post.filename}</h3>
<p>{post.content}</p>
</li>
))}
</ul>
)
}
// تٌستدعى هذه الدالة أثناء البناء من جهة الخادم
// ولا تُتستدعى من جانب العميل، لذا يمكنك إنشاءاستعلام مباشر لقاعدة البياتات
export async function getStaticProps() {
const postsDirectory = path.join(process.cwd(), 'posts')
const filenames = await fs.readdir(postsDirectory)
const posts = filenames.map(async (filename) => {
const filePath = path.join(postsDirectory, filename)
const fileContents = await fs.readFile(filePath, 'utf8')
// ستحوّل أو تحلل هذا المحتوى عادة
// HTML إلى markdown كأن تحوّل
return {
filename,
content: fileContents,
}
})
//المنشورات كخاصيات أثناء البناء Blog سيتلقى المكّون
return {
props: {
posts: await Promise.all(posts),
},
}
}
export default Blog
استخدام getstaticprops مع TypeScript
بإمكانك استخدام النوع GetStaticProps
من المكتبة next
:
import { GetStaticProps } from 'next'
export const getStaticProps: GetStaticProps = async (context) => {
// ...
}
وإن كنت تريد استخدام الأنواع الاستدلالية inferred typings للخاصيات، بإمكانك استخدام <InferGetStaticPropsType<typeof getStaticProps
:
import { InferGetStaticPropsType } from 'next'
type Post = {
author: string
content: string
}
export const getStaticProps = async () => {
const res = await fetch('https://.../posts')
const posts: Post[] = await res.json()
return {
props: {
posts,
},
}
}
function Blog({ posts }: InferGetStaticPropsType<typeof getStaticProps>) {
// Post[] سيحلل البيانات وفق النوع
}
export default Blog
ستعمل الأنواع الضمنية أيضًا مع الدالة GetStaticProps
:
import { InferGetStaticPropsType } from 'next'
type Post = {
author: string
content: string
}
export const getStaticProps = async () => {
const res = await fetch('https://.../posts')
const posts: Post[] = await res.json()
return {
props: {
posts,
},
}
}
function Blog({ posts }: InferGetStaticPropsType<typeof getStaticProps>) {
//post[] سيحلل المنشورات إلى النوع
}
export default Blog
المصادر
- الصفحات Data fetching من توثيق Next.js الرسمي.