التعامل مع Search Params باستخدام nuqs في Next.js App Router

التعامل مع Search Params باستخدام nuqs في Next.js App Router

M. Zakyuddin Munziri

M. Zakyuddin Munziri

@zakiego

كتب أصلاً بـ Bahasa Indonesia.

الملخص

nuqs هي مكتبة لإدارة حالة search params لـ Next.js.

السلوك الافتراضي لـ nuqs هو أولوية العميل (client-first)، مما يعني أنه عند تحديث search params، لن تتم إعادة عرض صفحة الويب. هذا أمر رائع إذا كانت قيمة search params تحتاج فقط للقراءة من جانب العميل.

ومع ذلك، إذا كانت القيمة بحاجة للقراءة من قبل الخادم، فلن يتم اكتشاف التغييرات. لتفعيل إعادة العرض حتى يتمكن الخادم من قراءة التغييرات، تحتاج إلى إضافة الخيار { shallow: false }.

هذا يختلف عن next-query-params التي تتبنى نهج أولوية الخادم (server-first)، مما يعني أن كل تغيير في القيمة يُقرأ فوراً من قبل الخادم.

جرّب الفرق بين search params من جانب العميل وجانب الخادم في nuqs على nuqs-playground.vercel.app

بالنسبة لـ next-query-params، يمكنك تجربتها على seach-params-playground.vercel.app

المقدمة

هذا المقال هو استمرار لـ إنشاء مكون البحث في Next.js App Router. سابقاً، استخدمنا مكتبة next-query-params لإدارة search params. هذه المرة سنتعامل مع nuqs.

في الواقع، جربت nuqs من قبل. لكن بسبب المعرفة المحدودة، لم أستمر في استخدامها.

شكراً لـ @alfonsusac الذي حفزني لقراءة توثيق nuqs بشكل أعمق.

نظرة عامة

nuqs تعرّف نفسها بأنها "مدير حالة search params آمن النوع لـ Next.js".

لنبدأ. بالطبع، الإطار المستخدم في هذا المقال هو Next.js.

أولاً، قم بتثبيت nuqs.

pnpm add nuqs

أنشئ ملف مكون يحتوي على <input/>، ثم أعد توجيه قيمة onChange إلى search params باستخدام useQueryState.

// src/app/client.tsx

'use client'

import { useQueryState } from 'nuqs'

export function Demo() {
  const [name, setName] = useQueryState("name");
  return (
    <>
      <input value={name || ""} onChange={(e) => setName(e.target.value)} />
      <p>Hello, {name}!</p>
    </>
  );
}

لماذا نحتاج لكتابة "use client" في أعلى السطر؟

لأنه منذ تقديم نموذج App Router في Next.js، كل مكون هو مكون خادم بشكل افتراضي. ومع ذلك، في هذه الحالة، نحتاج إلى onChange من <input/> وهو مكون عميل. لذلك، نحتاج لكتابة "use client" في السطر الأعلى لإخبار React أن هذا مكون عميل (Client Components).

أخيراً، استورد مكون <Demo/> الذي أنشأناه إلى /src/app/hello/page.tsx.

النتيجة هي أنه في كل مرة تدخل قيمة في <input/>، سيتم تحديث search params فوراً.

على سبيل المثال، example.com/hello ستتغير إلى example.com/hello?name=zaki.

لمزيد من الأمثلة، تحقق من nuqs.47ng.com/playground.

الفرق بين nuqs و next-query-params

سابقاً، استخدمت nuqs في هذه التغريدة. الفرق الأكثر وضوحاً بين nuqs و next-query-params هو:

  • nuqs تعمل على أولوية العميل 
  • بينما next-query-params هي أولوية الخادم

ما الفرق؟

يمكنك تجربة الفرق مباشرة بين أولوية العميل (nuqs-playground.vercel.app/nuqs-client) وأولوية الخادم (nuqs-playground.vercel.app/nuqs-server)

مع كون nuqs أولوية العميل، لا يمكننا الوصول إلى search params من جانب الخادم.

على سبيل المثال، نزور الصفحة example.com/hello.

ثم، عند كتابة اسم في الإدخال، يتغير الرابط إلى example.com/hello?name=zaki.

على الرغم من تغيّر الرابط، لأن nuqs هي أولوية العميل، ستظل قيمة name التي نحصل عليها من search params فارغة، إذا استخدمنا جانب الخادم.

nuqs بشكل افتراضي لا تفعّل تحديث الصفحة للخادم. لذا حتى لو تغيّر الرابط في متصفحنا إلى example.com/hello?name=zaki، يظل الخادم يعتبرنا في صفحة example.com/hello فقط.

interface Props {
  searchParams: {
    name?: string;
  };
}

export default async function Page(props: Props) {
  const { searchParams } = props;
  const { name } = searchParams;

  return (
    <div>
      value from server: {name}
    </div>
  );
}

ومع ذلك، الأمر مختلف في مكونات العميل، مثل <Demo/> السابق.

دعني أضع الكود مرة أخرى.

// src/app/client.tsx

'use client'

import { useQueryState } from 'nuqs'

export function Demo() {
  const [name, setName] = useQueryState("name");
  return (
    <>
      <input value={name || ""} onChange={(e) => setName(e.target.value)} />
      <p>Hello, {name}!</p>
    </>
  );
}

في هذا الكود، سيتم قراءة قيمة name فوراً، حتى لو لم نقم بتحديث الصفحة للخادم.

هذا عكس next-query-params، حيث في كل مرة تقوم بتحديث القيمة في <input/>، سيتم تفعيل تحديث الصفحة.

نتيجة لذلك، عندما يتحدث الرابط من example.com/hello إلى example.com/hello?name=zaki، يتعرف الخادم فوراً على أننا موجودون بالفعل في الرابط example.com/hello?name=zaki.

nuqs لكن من جانب الخادم

بعد القراءة بعناية أكبر، على الرغم من أن nuqs هي أولوية العميل، لا يزال بإمكاننا تشغيل إعادة العرض بإضافة { shallow: false }.

التوثيق nuqs.47ng.com/docs/options

useQueryState("foo", { shallow: false });

مع الإعداد أعلاه، يمكننا الحصول على search params من خلال جانب الخادم.

يمكنك تجربتها هنا nuqs-playground.vercel.app/nuqs-server.

هدية

إليك بعض الردود من مؤلف nuqs مباشرة:

أيضاً، اتضح أن nuqs تُستخدم من قبل vercel.com أيضاً

الخاتمة

nuqs لديها تجربة مطور (DX) أفضل مقارنة بـ next-query-params، لأنك لا تحتاج لإضافة كود لميزة التخطيط.

ومع ذلك، لأن nuqs هي أولوية العميل، لا يمكن الحصول على تغييرات قيمة search params مباشرة من جانب الخادم، إلا باستخدام { shallow: false }. هذا يختلف عن next-query-params التي هي أولوية الخادم من البداية، لذا يمكن قراءة تغييرات القيمة من قبل الخادم فوراً.

في النهاية، كل شيء يعود للمطور. الأسئلة هي:

  1. هل تقوم بالجلب من جانب الخادم أم جانب العميل؟
  2. بعد ذلك، هل تحتاج قيمة search params لتكون قابلة للقراءة من قبل الخادم؟ لأن في بعض الحالات، لا يجب أن تكون search params قابلة للقراءة فوراً من قبل الخادم

هذا كل شيء، شكراً لكم.


انتهت الكتابة يوم الخميس، 11 أبريل 2024 الساعة 13:39، اليوم الثاني من العيد.

مقالات أخرى

توقفت عن الحفر في السجلات

توقفت عن الحفر في السجلات

تغير تصحيح الأخطاء (Debugging) عندما توقفت عن قراءة السجلات يدوياً وبدأت في استخدام وكلاء الذكاء الاصطناعي لربط الأخطاء عبر بيانات المراقبة - وصول أسرع للسبب الجذري، وطرق مسدودة أقل.

السرعة لم تكن أبداً الجزء الصعب في CI/CD

السرعة لم تكن أبداً الجزء الصعب في CI/CD

خطوط الأنابيب السريعة لا تزيل الخوف من الشحن. الثقة تأتي من التراجع الآمن، أعلام الميزات، والأنظمة التي تتصرف بشكل يمكن التنبؤ به عندما تسوء الأمور.