الفرق بين المراجعتين ل"Next.js/Routing"

من موسوعة حسوب
اذهب إلى التنقل اذهب إلى البحث
سطر 1: سطر 1:
 
<noinclude>{{DISPLAYTITLE:توجيه المسارات في Next.js}}</noinclude>
 
<noinclude>{{DISPLAYTITLE:توجيه المسارات في Next.js}}</noinclude>
تمتلك موجهًا للمسارات يعتمد على نظام ملفات مبني على مفهوم [[Next.js/pages|الصفحات]]. فعندما يُضاف ملف إلى المجلد <code>pages</code> سيُتاح مباشرة كوجهة (أو مسار). يمكن استخدام الملفات ضمن هذا المجلد لتعريف مختلف الأنماط.
+
تمتلك Next.js موجهًا للمسارات يعتمد على نظام ملفات مبني على مفهوم [[Next.js/pages|الصفحات]]. فعندما يُضاف ملف إلى المجلد <code>pages</code> سيُتاح مباشرة كوجهة (أو مسار). يمكن استخدام الملفات ضمن هذا المجلد لتعريف مختلف الأنماط.
  
 
== أنماط الوجهات في Next.js ==
 
== أنماط الوجهات في Next.js ==
تدعم Next.js عددًا من أنماط الوجهات سنتعرف عليها تاليًا.
+
تدعم Next.js عددًا من أنماط الوجهات سنتعرف عليها تباعًا.
  
 
=== الوجهات الخاصة بالصفحة Index ===
 
=== الوجهات الخاصة بالصفحة Index ===
سيحدد الموّجه تلقائيًا موقع الصفحات التي تُدعى <code>index</code> بالنسبة إلى الملف الجذري كما في الأمثلة التالية:<syntaxhighlight lang="bash">
+
سيحدد الموجّه تلقائيًا موقع الصفحات التي تُدعى <code>index</code> بالنسبة إلى الملف الجذري كما في الأمثلة التالية:<syntaxhighlight lang="bash">
 
pages/index.js → /
 
pages/index.js → /
  
سطر 14: سطر 14:
  
 
=== الوجهات المتداخلة ===
 
=== الوجهات المتداخلة ===
يدعم الموّجه الملفات المتداخلة، فلو أنشأت هيكلية متداخلة لمجلد سيحدد الموّجه تلقائيًا موقع كل منها بنفس الطريقة السابقة:<syntaxhighlight lang="bash">
+
يدعم الموجّه الملفات المتداخلة، فلو أنشأت هيكلية متداخلة لمجلد سيحدد الموجّه تلقائيًا موقع كل منها بنفس الطريقة السابقة:<syntaxhighlight lang="bash">
 
pages/blog/first-post.js → /blog/first-post
 
pages/blog/first-post.js → /blog/first-post
  
سطر 27: سطر 27:
  
 
pages/post/[...all].js → /post/* (/post/2020/id/title)
 
pages/post/[...all].js → /post/* (/post/2020/id/title)
</syntaxhighlight>وسنتعرف أكثر على الوجهات الديناميكة تاليًا في صفحة التوثيق هذه.
+
</syntaxhighlight>سنتعرف أكثر على الوجهات الديناميكة تاليًا في صفحة التوثيق هذه.
  
 
== الربط ما بين الصفحات في Next.js ==
 
== الربط ما بين الصفحات في Next.js ==
سطر 62: سطر 62:
  
 
`/blog/hello-world` → `pages/blog/[slug].js`
 
`/blog/hello-world` → `pages/blog/[slug].js`
</syntaxhighlight>إن كل مكوّن <code></ Link></code> في نافذة العرض (بشكلها الأساسي أو بعد تمرير محتويات الشاشة) سيُحضَر مسبقًا بشكل افتراضي (بما في ذلك البيانات المتعلقة به) للصفحات باستخدام [[Next.js/data fetching|التوليد الساكن]] Static Generation. ولن تُحضر البيانات الناتجة عن تصيير الوجهات من [[Next.js/data fetching|جانب الخادم]] server-rendered بشكل مسبق.
+
</syntaxhighlight>إن كل مكوّن <code></ Link></code> في نافذة العرض (بشكلها الأساسي أو بعد تمرير محتويات الشاشة) سيُحضَر مسبقًا بشكل افتراضي (بما في ذلك البيانات المتعلقة به) للصفحات باستخدام [[Next.js/data fetching|التوليد الساكن]] Static Generation. ولن تُحضر البيانات الناتجة عن تصيير الوجهات من [[Next.js/data fetching|جانب الخادم]] server-rendered مسبقَا.
  
 
=== الارتباط بمسارات ديناميكية ===
 
=== الارتباط بمسارات ديناميكية ===
سطر 109: سطر 109:
  
 
* <code>pathname</code>: هو اسم الصفحة الموجودة في المجلد <code>pages</code>، وهي<code>blog/[slug]/</code> في مثالنا.
 
* <code>pathname</code>: هو اسم الصفحة الموجودة في المجلد <code>pages</code>، وهي<code>blog/[slug]/</code> في مثالنا.
* <code>query</code>: وهو كائن يحتوي على جزء ديناميكي، وهو <code>slug</code> في حالتنا.
+
* <code>query</code>: هو كائن يحتوي على جزء ديناميكي، وهو <code>slug</code> في حالتنا.
  
 
=== الدفع بالموجّه ===
 
=== الدفع بالموجّه ===
سطر 115: سطر 115:
  
 
== الوجهات الديناميكية في Next.js ==
 
== الوجهات الديناميكية في Next.js ==
لا يُعد تحديد المسارات مسبقًا أمرًا كافيًا للتطبيقات المعقدة، لهذا تتيح لك إمكانية إضافة أقواس مربعة حول صفحة (<code>[param]</code>) لإنشاء وجهة ديناميكة.
+
لا يُعد تحديد المسارات مسبقًا أمرًا كافيًا للتطبيقات المعقدة، لهذا تتيح لك Next.js إمكانية إضافة أقواس مربعة حول صفحة (<code>[param]</code>) لإنشاء وجهة ديناميكة.
  
لنتأمل الصفحة التالية <code>pages/post/[pid].js</code>:<syntaxhighlight lang="javascript">
+
لنتأمل الصفحة التالية <code>pages/post/[pid].js</code>:<syntaxhighlight lang="javascript">
 
import { useRouter } from 'next/router'
 
import { useRouter } from 'next/router'
  
سطر 130: سطر 130:
 
</syntaxhighlight>تجري مطابقة أي وجهة مثل <code>post/1/</code> أو<code>post/abc/</code> وغيرها مع المسار <code>pages/post/[pid].js</code> وسيُرسل معامل المسار على شكل استعلام إلى الصفحة وسيُدمج مع بقية معاملات الاستعلام.
 
</syntaxhighlight>تجري مطابقة أي وجهة مثل <code>post/1/</code> أو<code>post/abc/</code> وغيرها مع المسار <code>pages/post/[pid].js</code> وسيُرسل معامل المسار على شكل استعلام إلى الصفحة وسيُدمج مع بقية معاملات الاستعلام.
  
ستمتلك الوجهة <code>post/abc/</code> مثلًا كائن الاستعلام <code>query</code> التالي:<syntaxhighlight lang="json">
+
تمتلك الوجهة <code>post/abc/</code> مثلًا كائن الاستعلام <code>query</code> التالي:<syntaxhighlight lang="json">
 
{ "pid": "abc" }
 
{ "pid": "abc" }
</syntaxhighlight>كما ستمتلك الوجهة <code>post/abc?foo=bar/</code> أيضًا كائن الاستعلام <code>query</code> التالي:<syntaxhighlight lang="json">
+
</syntaxhighlight>كما تمتلك الوجهة <code>post/abc?foo=bar/</code> أيضًا كائن الاستعلام <code>query</code> التالي:<syntaxhighlight lang="json">
 
{ "foo": "bar", "pid": "abc" }
 
{ "foo": "bar", "pid": "abc" }
</syntaxhighlight>لكن ستلغي معاملات الوجهة معاملات الاستعلام التي تتفق معها بالاسم. إذ ستمتلك الوجهة <code>post/abc?pid=123/</code> مثلًا كائن الاستعلام <code>query</code> التالي:<syntaxhighlight lang="json">
+
</syntaxhighlight>لكن معاملات الوجهة ستلغي معاملات الاستعلام التي تتفق معها بالاسم. إذ تمتلك الوجهة <code>post/abc?pid=123/</code> مثلًا كائن الاستعلام <code>query</code> التالي:<syntaxhighlight lang="json">
 
{ "pid": "abc" }
 
{ "pid": "abc" }
</syntaxhighlight>تعمل الوجهات التي تضم عدة أجزاء ديناميكية بنفس الطريقة، إذ ستطابق الصفحة <code>pages/post/[pid]/[comment].js</code> الوجهة <code>post/abc/a-comment/</code> وسيكون كائن الاستعلام <code>query</code> الخاص بها هو:<syntaxhighlight lang="json">
+
</syntaxhighlight>تعمل الوجهات التي تضم عدة أجزاء ديناميكية بنفس الطريقة، إذ تطابق الصفحة <code>pages/post/[pid]/[comment].js</code> الوجهة <code>post/abc/a-comment/</code> وسيكون كائن الاستعلام <code>query</code> الخاص بها هو:<syntaxhighlight lang="json">
 
{ "pid": "abc", "comment": "a-comment" }
 
{ "pid": "abc", "comment": "a-comment" }
</syntaxhighlight>تُعالح المسارات الديناميكية للتنقل بين الصفحات في جانب العميل بواسطة المكوِّن [[Next.js/next link|<code>next/link</code>]]. فإن أردنا الحصول على روابط إلى الوجهات التي ذكرناها سابقًا فستبدو كالتالي:<syntaxhighlight lang="javascript">
+
</syntaxhighlight>تُعالح المسارات الديناميكية للتنقل بين الصفحات في جانب العميل بواسطة المكوِّن [[Next.js/next link|<code>next/link</code>]]. فإن أردنا الحصول على روابط إلى الوجهات التي ذكرناها سابقًا، ستبدو كالتالي:<syntaxhighlight lang="javascript">
 
import Link from 'next/link'
 
import Link from 'next/link'
  
سطر 177: سطر 177:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== التقاط جميع الوجهات بشكل اختياري ===
+
=== التقاط جميع الوجهات اختياريًا ===
 
يمكن التقاط جميع الوجهات اختياريًا بإضافة المعامل بين قوسين مربعين مزدوجين مثل (<code><nowiki>[[...slug]]</nowiki></code>). إذ ستطابق الوجهة <code>pages/post/<nowiki>[[...slug]]</nowiki>.js</code> مثلًا المسارات <code>post/</code> و <code>post/a/</code> و <code>post/a/b/</code> وهكذا.
 
يمكن التقاط جميع الوجهات اختياريًا بإضافة المعامل بين قوسين مربعين مزدوجين مثل (<code><nowiki>[[...slug]]</nowiki></code>). إذ ستطابق الوجهة <code>pages/post/<nowiki>[[...slug]]</nowiki>.js</code> مثلًا المسارات <code>post/</code> و <code>post/a/</code> و <code>post/a/b/</code> وهكذا.
  
سطر 190: سطر 190:
 
=== تحفظات على المسارات الديناميكية في Next.js ===
 
=== تحفظات على المسارات الديناميكية في Next.js ===
  
* للوجهات المحددة مسبقًا الأفضلية على الوجهات الدينياميكية و التي لها الأفضلية على جميع المسارات الملتقطة. إليك بعض الأمثلة:
+
* للوجهات المحددة مسبقًا الأفضلية على الوجهات الديناميكية والتي لها الأفضلية على جميع المسارات الملتقطة. إليك بعض الأمثلة:
** <code>pages/post/create.js</code> يتطابق مع <code>post/create/</code>.
+
**<code>pages/post/create.js</code> يتطابق مع <code>post/create/</code>.
 
** <code>pages/post/[pid].js</code> يتطابق مع <code>post/1/</code> و <code>post/abc/</code> وليس مع <code>post/create/</code>.
 
** <code>pages/post/[pid].js</code> يتطابق مع <code>post/1/</code> و <code>post/abc/</code> وليس مع <code>post/create/</code>.
** <code>pages/post/[...slug].js</code> يتطابق مع <code>post/1/2/</code> و <code>post/a/b/c/</code> وليس مع <code>post/create/</code> و <code>post/abc/</code>.
+
** <code>pages/post/[...slug].js</code> يتطابق مع <code>post/1/2/</code> و <code>post/a/b/c/</code> وليس مع <code>post/create/</code> و <code>post/abc/</code>.
* ستُرطَّب الصفحات التي تُحسّن بشكل ساكن من خلال [[Next.js/automatic static optimization|المحسّن الساكن الآلي]] Automatic Static Optimization دون تزويدها بمعاملات وجهاتها، أي سيكون كائن الاستعلام <code>query</code> مصفوفة فارغة (<code>{}</code>). وبعد الترطيب ستدفع Next.js إلى تحديث التطبيق لتزويد مصفوفة الاستعلام بقيم المعاملات.  
+
* ستُرطَّب الصفحات التي تُحسّن بشكل ساكن من خلال [[Next.js/automatic static optimization|المحسّن الساكن الآلي]] Automatic Static Optimization دون تزويدها بمعاملات وجهاتها، أي سيكون كائن الاستعلام <code>query</code> مصفوفة فارغة (<code>{}</code>). وبعد الترطيب ستدفع Next.js نحو تحديث التطبيق لتزويد مصفوفة الاستعلام بقيم المعاملات.
  
 
== الوجهات القسرية في Next.js ==
 
== الوجهات القسرية في Next.js ==
يغطي الكائن [[Next.js/next link|<code>next/link</code>]] كل احتياجاتك في التوجه إلى الموارد و الصفحات، لكن بإمكانك أيضًا التنقل بين الصفحات في جانب العميل دون الحاجة إليه (الق نظرة على [[Next.js/next router|توثيق الواجهة البرمجية المتعلق بالوجهات]]).
+
يغطي الكائن [[Next.js/next link|<code>next/link</code>]] كل احتياجاتك في التوجه إلى الموارد والصفحات، لكن بإمكانك أيضًا التنقل بين الصفحات في جانب العميل دون الحاجة إليه (الق نظرة على [[Next.js/next router|توثيق الواجهة البرمجية المتعلق بالوجهات]]).
  
 
يظهر المثال التالي كيفية التنقل بين الصفحات باستخدام <code>useRouter</code>:<syntaxhighlight lang="javascript">
 
يظهر المثال التالي كيفية التنقل بين الصفحات باستخدام <code>useRouter</code>:<syntaxhighlight lang="javascript">
سطر 214: سطر 214:
  
 
== التوجه السطحي في Next.js ==
 
== التوجه السطحي في Next.js ==
يتيح لك التوجه السطحي Shallow routing تغيير عنوان URL دون تنفيذ طرق إحضار البيانات مرة أخرى بما فيها <code>getServerSideProps</code> و <code>getStaticProps</code> و <code>getInitialProps</code>. ستحصل على المسار الحديث ومصفوفة الاستعلام الحديثة من خلال الكائن [[Next.js/next router|<code>router</code>]] (الذي يضيفه <code>useRouter</code> أو <code>withRouter</code>) دون أن يفقد المكوّن حالته.
+
يتيح لك التوجه السطحي Shallow routing تغيير عنوان URL دون تنفيذ طرق إحضار البيانات مرة أخرى بما فيها <code>getServerSideProps</code> و <code>getStaticProps</code> و <code>getInitialProps</code>. ستحصل على المسار الحديث ومصفوفة الاستعلام الحديثة من خلال الكائن [[Next.js/next router|<code>router</code>]] (الذي يضيفه <code>useRouter</code> أو <code>withRouter</code>) دون أن يفقد المكوّن حالته.
  
 
لتمكين التوجه السطحي، اضبط قيمة الخيار <code>shallow</code> على <code>true</code>. إليك مثالًا:<syntaxhighlight lang="javascript">
 
لتمكين التوجه السطحي، اضبط قيمة الخيار <code>shallow</code> على <code>true</code>. إليك مثالًا:<syntaxhighlight lang="javascript">
سطر 235: سطر 235:
  
 
export default Page
 
export default Page
</syntaxhighlight>سيثحدَّث عنوان URL إلى <code>?counter=10/</code>،لكن لن تُستبدل الصفحة بل حالة الوجهة فقط.
+
</syntaxhighlight>سيُحدَّث عنوان URL إلى <code>?counter=10/</code>، لكن لن تُستبدل الصفحة بل حالة الوجهة فقط.  
  
 
يمكنك أن ترى أيضًا كيف يتغير عنوان URL بواسطة المكوّن <code>componentDidUpdate</code> كالتالي:<syntaxhighlight lang="javascript">
 
يمكنك أن ترى أيضًا كيف يتغير عنوان URL بواسطة المكوّن <code>componentDidUpdate</code> كالتالي:<syntaxhighlight lang="javascript">
 
componentDidUpdate(prevProps) {
 
componentDidUpdate(prevProps) {
 
   const { pathname, query } = this.props.router
 
   const { pathname, query } = this.props.router
   // تاكد من تغير الخاصية لتفادي الحلقات المفرغة
+
   // تأكد من تغير الخاصية لتفادي الحلقات المفرغة
 
   if (query.counter !== prevProps.router.query.counter) {
 
   if (query.counter !== prevProps.router.query.counter) {
 
     // أحضر البيانات وفق الاستعلام الجديد
 
     // أحضر البيانات وفق الاستعلام الجديد
سطر 250: سطر 250:
 
يعمل هذا التوجه مع عناوين URL التي تتغير في الصفحة الحالية. لنفترض مثلًا وجود صفحة أخرى تُدعى <code>pages/about.js</code> ومن ثم نفَّذت الأمر التالي:<syntaxhighlight lang="javascript">
 
يعمل هذا التوجه مع عناوين URL التي تتغير في الصفحة الحالية. لنفترض مثلًا وجود صفحة أخرى تُدعى <code>pages/about.js</code> ومن ثم نفَّذت الأمر التالي:<syntaxhighlight lang="javascript">
 
router.push('/?counter=10', '/about?counter=10', { shallow: true })
 
router.push('/?counter=10', '/about?counter=10', { shallow: true })
</syntaxhighlight>طالما أنها صفحة جديدة، فلن تُحمّل الصفحة الحالية بل تحمّل الجديدة وينتظر البيانات حتى تأتي حتى لو أردنا وجهة سطحية.
+
</syntaxhighlight>طالما أنها صفحة جديدة، فلن تُحمّل الصفحة الحالية بل تُحمّل الجديدة وتُنتظر البيانات حتى تأتي حتى لو أردنا وجهة سطحية.
  
 
== المصادر ==
 
== المصادر ==
  
 
* صفحات [https://nextjs.org/docs/routing Router] من توثيق Next.js الرسمي.
 
* صفحات [https://nextjs.org/docs/routing Router] من توثيق Next.js الرسمي.

مراجعة 15:19، 30 مايو 2022

تمتلك Next.js موجهًا للمسارات يعتمد على نظام ملفات مبني على مفهوم الصفحات. فعندما يُضاف ملف إلى المجلد pages سيُتاح مباشرة كوجهة (أو مسار). يمكن استخدام الملفات ضمن هذا المجلد لتعريف مختلف الأنماط.

أنماط الوجهات في Next.js

تدعم Next.js عددًا من أنماط الوجهات سنتعرف عليها تباعًا.

الوجهات الخاصة بالصفحة Index

سيحدد الموجّه تلقائيًا موقع الصفحات التي تُدعى index بالنسبة إلى الملف الجذري كما في الأمثلة التالية:

pages/index.js → /

pages/blog/index.js → /blog

الوجهات المتداخلة

يدعم الموجّه الملفات المتداخلة، فلو أنشأت هيكلية متداخلة لمجلد سيحدد الموجّه تلقائيًا موقع كل منها بنفس الطريقة السابقة:

pages/blog/first-post.js → /blog/first-post

pages/dashboard/settings/username.js → /dashboard/settings/username

الأقسام الديناميكية لوجهة

لمطابقة جزء ديناميكي من مسار بإمكانك استخدام صيغة الأقواس المربعة، وسيتيح لك ذلك مطابقة معاملات مسماة:

pages/blog/[slug].js → /blog/:slug (/blog/hello-world)

pages/[username]/settings.js → /:username/settings (/foo/settings)

pages/post/[...all].js → /post/* (/post/2020/id/title)

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

الربط ما بين الصفحات في Next.js

يتح لك موجّه Next.js الانتقال بين الصفحات في جانب العميل بشكل مشابهٍ للتطبيقات وحيدة الصفحة. يُستخدم مكوّن React الذي يُدعى Link في إنجاز هذا الأمر من جانب العميل:

import Link from 'next/link'

function Home() {
  return (
    <ul>
      <li>
        <Link href="/">
          <a>Home</a>
        </Link>
      </li>
      <li>
        <Link href="/about">
          <a>About Us</a>
        </Link>
      </li>
      <li>
        <Link href="/blog/hello-world">
          <a>Blog Post</a>
        </Link>
      </li>
    </ul>
  )
}

export default Home

يستخدم المثال السابق روابط عدة يتعلق كل منها بمسار (href) إلى صفحة معروفة:

`/``pages/index.js`

`/about``pages/about.js`

`/blog/hello-world``pages/blog/[slug].js`

إن كل مكوّن </ Link> في نافذة العرض (بشكلها الأساسي أو بعد تمرير محتويات الشاشة) سيُحضَر مسبقًا بشكل افتراضي (بما في ذلك البيانات المتعلقة به) للصفحات باستخدام التوليد الساكن Static Generation. ولن تُحضر البيانات الناتجة عن تصيير الوجهات من جانب الخادم server-rendered مسبقَا.

الارتباط بمسارات ديناميكية

يمكن استخدام الاستدلال لإنشاء مسار، وتظهر الفائدة من ذلك عندما يتضمن عنوان المسار أجزاءً ديناميكة. فلو أردت أن تعرض على سبيل المثال مجموعة من المنشورات التي مُرِّرت إلى المكوّن على شكل خاصية:

import Link from 'next/link'

function Posts({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>
          <Link href={`/blog/${encodeURIComponent(post.slug)}`}>
            <a>{post.title}</a>
          </Link>
        </li>
      ))}
    </ul>
  )
}

export default Posts

ملاحظة: استُخدم الكائن encodeURIComponent في المثال السابق للمحافظة على توافق المسار مع utf-8.

import Link from 'next/link'

function Posts({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>
          <Link
            href={{
              pathname: '/blog/[slug]',
              query: { slug: post.slug },
            }}
          >
            <a>{post.title}</a>
          </Link>
        </li>
      ))}
    </ul>
  )
}

export default Posts

بدلًا من استخدام طريقة الاستدلال لإنشاء المسار، استخدمنا في الحالة الثانية كائن URL كقيمة للخاصية href:

  • pathname: هو اسم الصفحة الموجودة في المجلد pages، وهيblog/[slug]/ في مثالنا.
  • query: هو كائن يحتوي على جزء ديناميكي، وهو slug في حالتنا.

الدفع بالموجّه

للوصول إلى الكائن في مكوّن React، يمكنك استخدام useRouter أو withRouter علمًا أنه من الأفضل استخدام useRouter عمومًا.

الوجهات الديناميكية في Next.js

لا يُعد تحديد المسارات مسبقًا أمرًا كافيًا للتطبيقات المعقدة، لهذا تتيح لك Next.js إمكانية إضافة أقواس مربعة حول صفحة ([param]) لإنشاء وجهة ديناميكة.

لنتأمل الصفحة التالية pages/post/[pid].js:

import { useRouter } from 'next/router'

const Post = () => {
  const router = useRouter()
  const { pid } = router.query

  return <p>Post: {pid}</p>
}

export default Post

تجري مطابقة أي وجهة مثل post/1/ أوpost/abc/ وغيرها مع المسار pages/post/[pid].js وسيُرسل معامل المسار على شكل استعلام إلى الصفحة وسيُدمج مع بقية معاملات الاستعلام. تمتلك الوجهة post/abc/ مثلًا كائن الاستعلام query التالي:

{ "pid": "abc" }

كما تمتلك الوجهة post/abc?foo=bar/ أيضًا كائن الاستعلام query التالي:

{ "foo": "bar", "pid": "abc" }

لكن معاملات الوجهة ستلغي معاملات الاستعلام التي تتفق معها بالاسم. إذ تمتلك الوجهة post/abc?pid=123/ مثلًا كائن الاستعلام query التالي:

{ "pid": "abc" }

تعمل الوجهات التي تضم عدة أجزاء ديناميكية بنفس الطريقة، إذ تطابق الصفحة pages/post/[pid]/[comment].js الوجهة post/abc/a-comment/ وسيكون كائن الاستعلام query الخاص بها هو:

{ "pid": "abc", "comment": "a-comment" }

تُعالح المسارات الديناميكية للتنقل بين الصفحات في جانب العميل بواسطة المكوِّن next/link. فإن أردنا الحصول على روابط إلى الوجهات التي ذكرناها سابقًا، ستبدو كالتالي:

import Link from 'next/link'

function Home() {
  return (
    <ul>
      <li>
        <Link href="/post/abc">
          <a>Go to pages/post/[pid].js</a>
        </Link>
      </li>
      <li>
        <Link href="/post/abc?foo=bar">
          <a>Also goes to pages/post/[pid].js</a>
        </Link>
      </li>
      <li>
        <Link href="/post/abc/a-comment">
          <a>Go to pages/post/[pid]/[comment].js</a>
        </Link>
      </li>
    </ul>
  )
}

export default Home

التقاط جميع الوجهات

بالإمكان توسعة الوجهات الديناميكية لمطابقة كل المسارات وذلك بإضافة ثلاث نقاط (...) داخل القوسين المربعين. إليك مثالًا:

  • تطابق الوجهة pages/post/[...slug].js المسار post/a/ كما تطابق post/a/b/ و post/a/b/c/ وهكذا. بإمكانك طبعًا اختيار أي اسم بدلًا من slug مثل [param...].

تُرسل معاملات البحث كمعاملات استعلام ( slug مثال على ذلك) إلى الصفحة، وتشكل المعاملات دائمًا مصفوفة. وبالتالي سيكون كائن الاستعلام عن المسار post/a/ مثلًا هو:

{ "slug": ["a"] }

في حالة post/a/b/ وأية مسارات مطابقة أخرى، ستُضاف البارمترات الجديدة إلى المصفوفة كالتالي:

{ "slug": ["a", "b"] }

التقاط جميع الوجهات اختياريًا

يمكن التقاط جميع الوجهات اختياريًا بإضافة المعامل بين قوسين مربعين مزدوجين مثل ([[...slug]]). إذ ستطابق الوجهة pages/post/[[...slug]].js مثلًا المسارات post/ و post/a/ و post/a/b/ وهكذا.

إن الاختلاف الرئيسي بين التقاط جميع الوجهات والتقاط جميع الوجهات اختياريًا هو أن الالتقاط الاختياري سيطابق أيضًا المسارات التي لا تضم معامل البحث (المسار post/ مثالًا).

سيكون كائن الاستعلام query التالي:

{ } //`/post` سيحصل على المسار 
{ "slug": ["a"] } //(مصفوفة وحيد العنصر) `/post/a` سيحصل على المسار 
{ "slug": ["a", "b"] } //(مصفوفة متعددة العناصر) `/post/a/b` سيحصل على

تحفظات على المسارات الديناميكية في Next.js

  • للوجهات المحددة مسبقًا الأفضلية على الوجهات الديناميكية والتي لها الأفضلية على جميع المسارات الملتقطة. إليك بعض الأمثلة:
    • pages/post/create.js يتطابق مع post/create/.
    • pages/post/[pid].js يتطابق مع post/1/ و post/abc/ وليس مع post/create/.
    • pages/post/[...slug].js يتطابق مع post/1/2/ و post/a/b/c/ وليس مع post/create/ و post/abc/.
  • ستُرطَّب الصفحات التي تُحسّن بشكل ساكن من خلال المحسّن الساكن الآلي Automatic Static Optimization دون تزويدها بمعاملات وجهاتها، أي سيكون كائن الاستعلام query مصفوفة فارغة ({}). وبعد الترطيب ستدفع Next.js نحو تحديث التطبيق لتزويد مصفوفة الاستعلام بقيم المعاملات.

الوجهات القسرية في Next.js

يغطي الكائن next/link كل احتياجاتك في التوجه إلى الموارد والصفحات، لكن بإمكانك أيضًا التنقل بين الصفحات في جانب العميل دون الحاجة إليه (الق نظرة على توثيق الواجهة البرمجية المتعلق بالوجهات).

يظهر المثال التالي كيفية التنقل بين الصفحات باستخدام useRouter:

import { useRouter } from 'next/router'

export default function ReadMore() {
  const router = useRouter()

  return (
    <button onClick={() => router.push('/about')}>
      Click here to read more
    </button>
  )
}

التوجه السطحي في Next.js

يتيح لك التوجه السطحي Shallow routing تغيير عنوان URL دون تنفيذ طرق إحضار البيانات مرة أخرى بما فيها getServerSideProps و getStaticProps و getInitialProps. ستحصل على المسار الحديث ومصفوفة الاستعلام الحديثة من خلال الكائن router (الذي يضيفه useRouter أو withRouter) دون أن يفقد المكوّن حالته.

لتمكين التوجه السطحي، اضبط قيمة الخيار shallow على true. إليك مثالًا:

import { useEffect } from 'react'
import { useRouter } from 'next/router'

// الحالي URL هو عنوان '/'
function Page() {
  const router = useRouter()

  useEffect(() => {
    // تنقَّل دائمًا بعد التصيير الأول
    router.push('/?counter=10', undefined, { shallow: true })
  }, [])

  useEffect(() => {
    // !تغيّر العداد
  }, [router.query.counter])
}

export default Page

سيُحدَّث عنوان URL إلى ?counter=10/، لكن لن تُستبدل الصفحة بل حالة الوجهة فقط. يمكنك أن ترى أيضًا كيف يتغير عنوان URL بواسطة المكوّن componentDidUpdate كالتالي:

componentDidUpdate(prevProps) {
  const { pathname, query } = this.props.router
  // تأكد من تغير الخاصية لتفادي الحلقات المفرغة
  if (query.counter !== prevProps.router.query.counter) {
    // أحضر البيانات وفق الاستعلام الجديد
  }
}

التحفظات على التوجه السطحي

يعمل هذا التوجه مع عناوين URL التي تتغير في الصفحة الحالية. لنفترض مثلًا وجود صفحة أخرى تُدعى pages/about.js ومن ثم نفَّذت الأمر التالي:

router.push('/?counter=10', '/about?counter=10', { shallow: true })

طالما أنها صفحة جديدة، فلن تُحمّل الصفحة الحالية بل تُحمّل الجديدة وتُنتظر البيانات حتى تأتي حتى لو أردنا وجهة سطحية.

المصادر

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