الفرق بين المراجعتين لصفحة: «Next.js/api data fetching»
لا ملخص تعديل |
لا ملخص تعديل |
||
سطر 95: | سطر 95: | ||
} | } | ||
} | } | ||
</syntaxhighlight> | |||
== الدالة غير المتزامنة <code>getServerSideProps</code> == | |||
عندما تُصدر الصفحة دالة تُدعى <code>getServerSideProps</code> (تصيير من جانب الخادم)، تُصيير هذه الصفحة مسبقًا عند كل طلب باستخدام البيانات المعادة من هذه الدالة. ولهذا الأمر فائدته إن كنت تريد إحضار البيانات التي تتغير أحيانًا، وتحديث الصفحة لعرض هذه البيانات الحالية:<syntaxhighlight lang="javascript"> | |||
export async function getServerSideProps(context) { | |||
return { | |||
props: {}, // تُمرر إلى مكون الصفحة على شكل خاصيات | |||
} | |||
} | |||
</syntaxhighlight>بإمكانك إدراج الوحدات البرمجية في أعلى مستوى كي تستخدمها مع <code>getServerSideProps</code>، ولن تُجمّع هذه الوحدات ضمن شيفرة جانب العميل (الواجهة الأمامية). أي بإمكانك كتابة الشيفرة التي تُنفّذ على الخادم مباشرة ضمن <code>getServerSideProps</code> بما في ذلك إحضار البيانات من قاعدة بيانات. | |||
=== الكائن <code>context</code> === | |||
تتلقى الدالة <code>getServerSideProps</code> معاملًا واحدًا يدعى <code>context</code>، وهو كائن يمتلك المفاتيح التالية: | |||
* <code>params</code>: إن استخدمت الصفحة [[Next.js/dynamic routes|مسارات ديناميكية]]، سيضم هذا المفتاح معاملات الوجهة. إذ تبدو هذه المعاملات على الشكل <code>{ ...:id}</code> إن كان اسم الصفحة مثلًا <code>[id].js</code> | |||
* <code>query</code>: قسم الاستعلام النصي من عنوان URL والمُحلَّل ككائن. | |||
* <code>req</code>: [[Node.js/http|كائن الرسائل الواردة في HTTP]] مع الخاصية الإضافية <code>cookies</code>، وهي كائن له مفاتيح نصية ترتبط مع القيم النصية لملفات تعريف الارتباط. | |||
* <code>res</code>: [[Node.js/http|كائن طلب استجابة HTTP]] (خادم فقط). | |||
* <code>preview</code>: يأخذ القيمة <code>true</code> عندما تكون الصفحة في [[Next.js/preview mode|وضع الاستعراض]]. | |||
* <code>previewData</code>: بيانات الاستعراض التي تضبطها <code>setPreviewData</code>. | |||
* <code>resolvedUrl</code>: نسخة عادية من عنوان <code>URL</code> المطلوب بعد تجريده من بادئة <code>_next/data</code> وذلك للتنقل في طرف العميل، وتتضمن قيم الاستعلام الأصلي. | |||
* <code>locale</code>: يضم الإعداد المحلي الفعّال (إن مُكِّن). | |||
* <code>locales</code>: يضم كل الإعدادات المحلية المدعومة (إن مُكِّن). | |||
* <code>defaultLocale</code>: يضم كل الإعدادات المحلية الافتراضية المهيأة (إن مُكِّن). | |||
=== القيم التي تعيدها الدالة <code>getServerSideProps</code> === | |||
لا بد أن تعيد هذه الدالة كائنًا له إحدى الخاصيات التالية: | |||
==== الخاصية <code>props</code> ==== | |||
وهو كائن من الشكل (مفتاح-قيمة) حيث يتلقى كل قيمة من مكوّن الصفحة. ينبغي أت يكون الكائن قابلًا للتحليل كي تُحلل الخاصيات الممرة باستخدام التابع <code>JSON.stringify</code>.<syntaxhighlight lang="javascript"> | |||
export async function getServerSideProps(context) { | |||
return { | |||
props: { message: `Next.js is awesome` }, // تمرر إلى مكون الصفحة كخاصيات | |||
} | |||
} | |||
</syntaxhighlight> | |||
==== الخاصية <code>notFound</code> ==== | |||
وهي قيمة منطقية تتيح للصفحة أن تعيد رمز الحالة 404 و<nowiki/>[[Next.js/custom error page|صفحة هذه الحالة]]. تُعيد الصفحة عندما تكون قيمة هذه الخاصية <code>true</code> رمز الحالة <code>404</code> حتى لو وُلِّدت الصفحة بنجاح سابقًا. إن الغاية من ذلك دعم بعض حالات الاستخدام مثل المحتوى الذي يولّده مستخدم ويُزال من قبله.<syntaxhighlight lang="javascript"> | |||
export async function getServerSideProps(context) { | |||
const res = await fetch(`https://.../data`) | |||
const data = await res.json() | |||
if (!data) { | |||
return { | |||
notFound: true, | |||
} | |||
} | |||
return { | |||
props: { data }, // يُمرر إلى مكوّن الصفحة كخاصيات | |||
} | |||
} | |||
</syntaxhighlight> | |||
==== الخاصية <code>redirect</code> ==== | |||
يتيح الكائن <code>redirect</code> إعادة التوجيه إلى مصادر داخلية أو خارجية، وينبغي أن يطابق الشكل <code>{ destination: string, permanent: boolean }</code>. قد تحتاج في حالات نادرة تعيين رموز حالة مخصصة لعملاء <code>HTTP</code> الأقدم كي يُعاد توجيههم بالشكل الصحيح. في حالات كهذه، استخدم الخاصية <code>statusCode</code> بدلًا من <code>permanent</code> لكن لا تستخدمهما معًا:<syntaxhighlight lang="javascript"> | |||
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: {}, //يُمرر إلى مكوّن الصفحة كخاصيات | |||
} | |||
} | |||
</syntaxhighlight> | |||
==== استخدام الدالة مع TypeScript ==== | |||
بإمكانك استخدام النوع <code>GetServerSideProps</code> من المكتبة <code>next</code>:<syntaxhighlight lang="javascript"> | |||
import { GetServerSideProps } from 'next' | |||
export const getServerSideProps: GetServerSideProps = async (context) => { | |||
// ... | |||
} | |||
</syntaxhighlight>وإن كنت تريد استخدام الأنواع الاستدلالية inferred typings للخاصيات، بإمكانك استخدام | |||
<code><InferGetServerSidePropsType<typeof 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>) { | |||
// سيحلل المنشورات وفق نوع البيانات | |||
} | |||
export default Page | |||
</syntaxhighlight> | </syntaxhighlight> | ||
مراجعة 05:26، 12 يوليو 2022
نستعرض في هذه الصفحة من التوثيق الدوال التي تستخدمها Next.js في إحضار البيانات.
الدالة غير المتزامنة getInitialProps
نصيحة هامة: يتيح لك استخدام إحدى الدالتين getStaticProps
أو getServerSideProps
بدلًا من getInitialProps
في إحضار البيانات أسلوبًا يجمع بين التوليد الساكن والتصيير من جانب الخادم.
تُمكّنك الدالة 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
المصادر
- الصفحات Data fetching من توثيق Next.js الرسمي.