النموذج (Form)
يمتد مكون <Form>
عنصر HTML <form>
لتوفير التحميل المسبق (prefetching) لواجهة التحميل (loading UI)، التنقل من جانب العميل (client-side navigation) عند الإرسال، والتحسين التدريجي (progressive enhancement).
هو مفيد للنماذج التي تقوم بتحديث معلمات البحث في URL لأنه يقلل من الكود المتكرر المطلوب لتحقيق ما سبق.
الاستخدام الأساسي:
import Form from 'next/form'
export default function Page() {
return (
<Form action="/search">
{/* عند الإرسال، سيتم إضافة قيمة الإدخال إلى
الـ URL، مثلاً /search?query=abc */}
<input name="query" />
<button type="submit">Submit</button>
</Form>
)
}
import Form from 'next/form'
export default function Search() {
return (
<Form action="/search">
{/* عند الإرسال، سيتم إضافة قيمة الإدخال إلى
الـ URL، مثلاً /search?query=abc */}
<input name="query" />
<button type="submit">Submit</button>
</Form>
)
}
المرجع
يعتمد سلوك مكون <Form>
على ما إذا كانت الخاصية action
تمرر كـ string
أو function
.
- عندما تكون
action
سلسلة نصية (string)، يتصرف<Form>
مثل نموذج HTML عادي يستخدم طريقةGET
. يتم ترميز بيانات النموذج في الـ URL كمعلمات بحث، وعند إرسال النموذج، يتم التنقل إلى الـ URL المحدد. بالإضافة إلى ذلك، يقوم Next.js بما يلي:- التحميل المسبق (Prefetches) للمسار عندما يصبح النموذج مرئيًا، مما يؤدي إلى تحميل مسبق لواجهة المستخدم المشتركة (مثل
layout.js
وloading.js
)، مما يؤدي إلى تنقل أسرع. - يقوم بـ التنقل من جانب العميل (client-side navigation) بدلاً من إعادة تحميل الصفحة بالكامل عند إرسال النموذج. هذا يحافظ على واجهة المستخدم المشتركة وحالة جانب العميل.
- التحميل المسبق (Prefetches) للمسار عندما يصبح النموذج مرئيًا، مما يؤدي إلى تحميل مسبق لواجهة المستخدم المشتركة (مثل
- عندما تكون
action
دالة (function) (إجراء خادم Server Action)، يتصرف<Form>
مثل نموذج React، بتنفيذ الإجراء عند إرسال النموذج.
خصائص action
(سلسلة نصية)
عندما تكون action
سلسلة نصية، يدعم مكون <Form>
الخصائص التالية:
الخاصية | مثال | النوع | مطلوب |
---|---|---|---|
action | action="/search" | string (URL أو مسار نسبي) | نعم |
replace | replace={false} | boolean | - |
scroll | scroll={true} | boolean | - |
prefetch | prefetch={true} | boolean | - |
action
: الـ URL أو المسار للتنقل إليه عند إرسال النموذج.- سلسلة نصية فارغة
""
ستؤدي إلى التنقل إلى نفس المسار مع تحديث معلمات البحث.
- سلسلة نصية فارغة
replace
: يستبدل حالة التاريخ الحالية بدلاً من إضافة جديدة إلى مكدس تاريخ المتصفح. الافتراضي هوfalse
.scroll
: يتحكم في سلوك التمرير أثناء التنقل. الافتراضي هوtrue
، مما يعني أنه سيتم التمرير إلى أعلى المسار الجديد، والحفاظ على موضع التمرير للتنقل للخلف وللأمام.prefetch
: يتحكم فيما إذا كان يجب تحميل المسار مسبقًا عندما يصبح النموذج مرئيًا في نطاق رؤية المستخدم. الافتراضي هوtrue
.
خصائص action
(دالة)
عندما تكون action
دالة، يدعم مكون <Form>
الخاصية التالية:
الخاصية | مثال | النوع | مطلوب |
---|---|---|---|
action | action={myAction} | function (إجراء خادم) | نعم |
action
: إجراء الخادم الذي سيتم استدعاؤه عند إرسال النموذج. راجع وثائق React للمزيد.
جيد معرفته: عندما تكون
action
دالة، يتم تجاهل خصائصreplace
وscroll
.
محاذير
formAction
: يمكن استخدامها في حقول<button>
أو<input type="submit">
لتجاوز خاصيةaction
. سيقوم Next.js بتنفيذ تنقل من جانب العميل، لكن هذا الأسلوب لا يدعم التحميل المسبق.- عند استخدام
basePath
، يجب أيضًا تضمينه في مسارformAction
. مثلاًformAction="/base-path/search"
.
- عند استخدام
key
: تمرير خاصيةkey
إلىaction
من نوع سلسلة نصية غير مدعوم. إذا كنت ترغب في إطلاق إعادة عرض أو تنفيذ تغيير، فكر في استخدامaction
كدالة بدلاً من ذلك.
onSubmit
: يمكن استخدامه لمعالجة منطق إرسال النموذج. ومع ذلك، استدعاءevent.preventDefault()
سيتجاوز سلوك<Form>
مثل التنقل إلى الـ URL المحدد.method
,encType
,target
: غير مدعومة لأنها تتجاوز سلوك<Form>
.- بالمثل، يمكن استخدام
formMethod
،formEncType
، وformTarget
لتجاوز خصائصmethod
،encType
، وtarget
على التوالي، واستخدامها سيعيد إلى سلوك المتصفح الافتراضي. - إذا كنت بحاجة إلى استخدام هذه الخصائص، استخدم عنصر HTML
<form>
بدلاً من ذلك.
- بالمثل، يمكن استخدام
<input type="file">
: استخدام نوع الإدخال هذا عندما تكونaction
سلسلة نصية سيطابق سلوك المتصفح بإرسال اسم الملف بدلاً من كائن الملف.
أمثلة
نموذج بحث يؤدي إلى صفحة نتائج البحث
يمكنك إنشاء نموذج بحث يؤدي إلى صفحة نتائج البحث عن طريق تمرير المسار كـ action
:
import Form from 'next/form'
export default function Page() {
return (
<Form action="/search">
<input name="query" />
<button type="submit">Submit</button>
</Form>
)
}
import Form from 'next/form'
export default function Page() {
return (
<Form action="/search">
<input name="query" />
<button type="submit">Submit</button>
</Form>
)
}
عندما يقوم المستخدم بتحديث حقل إدخال الاستعلام وإرسال النموذج، سيتم ترميز بيانات النموذج في الـ URL كمعلمات بحث، مثلاً /search?query=abc
.
جيد معرفته: إذا قمت بتمرير سلسلة نصية فارغة
""
إلىaction
، سينتقل النموذج إلى نفس المسار مع تحديث معلمات البحث.
في صفحة النتائج، يمكنك الوصول إلى الاستعلام باستخدام خاصية searchParams
لـ page.js
واستخدامها لجلب البيانات من مصدر خارجي.
import { getSearchResults } from '@/lib/search'
export default async function SearchPage({
searchParams,
}: {
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
}) {
const results = await getSearchResults((await searchParams).query)
return <div>...</div>
}
import { getSearchResults } from '@/lib/search'
export default async function SearchPage({ searchParams }) {
const results = await getSearchResults((await searchParams).query)
return <div>...</div>
}
عندما يصبح <Form>
مرئيًا في نطاق رؤية المستخدم، سيتم تحميل واجهة المستخدم المشتركة (مثل layout.js
و loading.js
) في صفحة /search
مسبقًا. عند الإرسال، سينتقل النموذج فورًا إلى المسار الجديد ويعرض واجهة تحميل أثناء جلب النتائج. يمكنك تصميم واجهة الانتظار باستخدام loading.js
:
export default function Loading() {
return <div>Loading...</div>
}
export default function Loading() {
return <div>Loading...</div>
}
لتغطية الحالات عندما لم يتم تحميل واجهة المستخدم المشتركة بعد، يمكنك عرض ردود فعل فورية للمستخدم باستخدام useFormStatus
.
أولاً، قم بإنشاء مكون يعرض حالة تحميل عندما يكون النموذج قيد الانتظار:
ثم، قم بتحديث صفحة نموذج البحث لاستخدام مكون SearchButton
:
import Form from 'next/form'
import { SearchButton } from '@/ui/search-button'
export default function Page() {
return (
<Form action="/search">
<input name="query" />
<SearchButton />
</Form>
)
}
التغييرات باستخدام إجراءات الخادم (Server Actions)
يمكنك تنفيذ التغييرات عن طريق تمرير دالة إلى خاصية action
.
import Form from 'next/form'
import { createPost } from '@/posts/actions'
export default function Page() {
return (
<Form action={createPost}>
<input name="title" />
{/* ... */}
<button type="submit">Create Post</button>
</Form>
)
}
import Form from 'next/form'
import { createPost } from '@/posts/actions'
export default function Page() {
return (
<Form action={createPost}>
<input name="title" />
{/* ... */}
<button type="submit">Create Post</button>
</Form>
)
}
بعد التغيير، من الشائع إعادة التوجيه إلى المورد الجديد. يمكنك استخدام دالة redirect
من next/navigation
للتنقل إلى صفحة المنشور الجديد.
جيد معرفته: بما أن "الوجهة" لإرسال النموذج غير معروفة حتى يتم تنفيذ الإجراء، لا يمكن لـ
<Form>
تحميل واجهة المستخدم المشتركة مسبقًا تلقائيًا.
'use server'
import { redirect } from 'next/navigation'
export async function createPost(formData: FormData) {
// إنشاء منشور جديد
// ...
// إعادة التوجيه إلى المنشور الجديد
redirect(`/posts/${data.id}`)
}
'use server'
import { redirect } from 'next/navigation'
export async function createPost(formData) {
// إنشاء منشور جديد
// ...
// إعادة التوجيه إلى المنشور الجديد
redirect(`/posts/${data.id}`)
}
ثم، في الصفحة الجديدة، يمكنك جلب البيانات باستخدام خاصية params
:
import { getPost } from '@/posts/data'
export default async function PostPage({
params,
}: {
params: Promise<{ id: string }>
}) {
const { id } = await params
const data = await getPost(id)
return (
<div>
<h1>{data.title}</h1>
{/* ... */}
</div>
)
}
import { getPost } from '@/posts/data'
export default async function PostPage({ params }) {
const { id } = await params
const data = await getPost(id)
return (
<div>
<h1>{data.title}</h1>
{/* ... */}
</div>
)
}
راجع وثائق إجراءات الخادم (Server Actions) للمزيد من الأمثلة.