بناء خطافين لإدارة Next.js Queries

بناء خطافين لإدارة Next.js Queries

أحيانًا يكون لدينا واجهات برمجة تطبيقات كاملة، لكن احيانا لايكون كذلك. اذن لا يمكننا أن نتوقع كل ما نحتاجه في أداة واحدة محددة.
ينطبق الأمر نفسه في React أو Next. لا يمكنهم تنفيذ جميع الخطافات التي نحتاجها، لكن يمكنهم السماح لنا بذلك. التصريح الذي أتحدث عنه هو شيء مثل IOC.

ما هي المشكلة؟ 🤔

المشكلة أنني أردت أن تكون الحالة نفسها في المكون الخاص بي في query. هذا ممكن، ولكن ليس من السهل الكتابة في كل مكون.

دعنا نقدم بعض الحلول التي لا أحبها!!!

const [count, setCount] = useState(0);

const { pathname, push, asPath } = useRouter();

const [query, setQuery] = useState({});

useEffect(() => {
  push(pathname, { query: { count: count } }, { shallow: true });
}, [count]);

useEffect(() => {
    setQuery(parseUrl(asPath).query);
}, [asPath]);

ليس لدي أي مشكلة مع هذا الرمز ولكن تخيل أنه عندما يكون لدينا الكثير من المكونات التي نحتاجها لإدارة الاستعلام فيها (query)، سيكون الأمر فظيعًا.

سنستخدم خطاف الموجه (router hook) في كل مكون، اثنان useEffect (يمكننا وضعهما في واحد)، و سنحتاج إلى تحليل المسار ودفع التغييرات إلى query (الاستعلام). من الصعب بالنسبة لي القيام بمثل هذا الشيء.

الحل لبناء خطافين😍

أعتقد أنه يمكننا أحيانًا كتابة المزيد من التعليمات البرمجية التي يمكن أن تجعل حياتنا أسهل، وهذا ما سنفعله. سنستخدم المزيد من الوظائف والخطافات الجديدة. فيما يلي تطبيق نمط بسيط مثل useQuery أو useEffect، شاهد هذا:

const {
  queries,
  addQueries,
  deleteQuery,
  clearQueries
} = useNextQuery(() => ({}));

في الخطاف الأول الذي نقوم به، يمكننا رؤية حالة وإضافة Queries جديدة وأيضًا حذف واحدة. رائع!

useNextQueryEffect(() => {
  return { count: count };
}, [count]);

والخطاف الثاني مبني على الأول، وهو مشابه لـ useEffect. فهو يأخذ بعض التبعيات وعندما يتغير، فإنه يعين المكون السابق كمكون query جديد. إذا كانت الوسيطة الأخيرة صحيحة، فسوف تمسح query السابق.

بناء خطافين لإدارة Next.js Queries

نحتاج أولاً إلى الوصول لنظام التوجيه في Next.js ، لذلك سنستخدم الخطاف useRouter.

const useNextQuery = (initialQuery = {}, shallow = true) => {
  const { asPath, push, pathname } = useRouter();
};

إذا كنت لا تعرف شيئًا عن asPath و push و pathname ، فإليك شرح Next.js docs:

asPath: المسار الفعلي (بما في ذلك الاستعلام) المعروض في المتصفح.

اسم المسار: المسار الحالي. هذا هو مسار الصفحة / الصفحات

push: يتعامل مع الانتقالات من جانب المستخدم، وهذه الطريقة مفيدة للحالات التي يكون فيها next / link غير كافٍ.

في هذا الخطاف، نأخذ الوسيطة الأولى من المستخدم كحالة أولية (أو استعلام أولي)، والثاني هو الانتقال shallow، سأتحدث عنه.

الحالة الأولية (Initial state)

عندما يتصاعد المكون، نحتاج إلى الوصول إلى query في عنوان url وإعادتها كأول استعلامات.

const [state, setState] = useState(() => {
  const { query: initialRouteQuery } = queryString.parseUrl(asPath);
  return { ...initialQuery, ...initialRouteQuery };
})

في useState ، نجتاز الاستدعاء، يسمى lazy initialization، وهو شيء مثالي للأداء. تعد حزمة Query-string مفيدة جدًا ، فنحن نستخدمها لتحليل سلسلة asPath ، ولكن إذا كنت لا ترغب في استخدام مكتبات أجنبية ، فيمكنك تنفيذ الخوارزمية الخاصة بك. إذا مررنا استعلامنا الأولي إلى الخطاف، فسيتم مزجه مع query الأولي المستند إلى عنوان url ، ثم نقوم بتعيين query في عنوان url. وبالتالي:

خذ عنصر طلب البحث الأولية على أنها initialQuery

تحويل asPath إلى كائن يسمى initialRouteQuery

امزجهم واضبطهم أو ادفعهم (في الخطوات التالية)

Push

يجب أن يكون الاستعلام (query) محدثًا وعندما تتغير الحالة يجب أن يتغير Query أيضًا. يمكننا استخدام useEffect لمشاهدة تغيرات الحالة.

useEffect(() => {
  push(
    pathname,
    {
      query: state
    },
    { shallow: shallow }
  );
}, [state]);

لذلك كلما تغيرت حالة Query ، ندفع التغييرات إلى المسار. لا نريد تغيير المسار ، لذلك نحتفظ بنفس اسم المسار. يمنحنا خيار shallow القدرة على إدارة إعادة التشغيل من جانب الخادم ونأخذها من المعلمة الثانية في useNextQuery.

تحديث Queries

يجب أن تكون Query حديثة أيضًا، ويمكن القيام بذلك من خلال الاستماع إلى asPath (لست متأكدًا من أداء هذا الحل ، إذا كان لديك حل أفضل ، فقم بالتعليق لي).

useEffect(() => {
  const { query } = queryString.parseUrl(asPath);
  setState({ ...state, ...query });
}, [asPath]);

هنا عندما تتغير الحالة ، سيعمل useEffect العلوي مرة أخرى ويحافظ على تحديث الحالة و Query.

الخطوات

إنها خطوة بسيطة ، نقوم فقط بإنشاء ثلاث وظائف تقوم بتعديل الحالة ثم يتغير Query.

const addQueries = (newQueries) =>
  setState((prevState) => ({ ...prevState, ...newQueries }));

const deleteQuery = (oldQuery) =>
  setState((prevState) => {
    const { [oldQuery]: deletedQuery, ...rest } = prevState;
    return rest;
  });

const clearQueries = () => setState({});

return {
  queries: state,
  addQueries,
  deleteQuery,
  clearQueries
};

انتهينا من الخطاف الأول، وهناك خطاف آخر صغير ثم 💣💥!

useNextQueryEffect

أنا حقًا أحب هذا! في كل مرة أنظر إليها ، أشعر بمدى سهولة حياتي الآن (مبالغة قليلة). نعطيها التبعيات وكلما تغيرت ، فإن هذا الخطاف سيدفع Query بناءً على القيمة التي تم إرجاعها من خلال الاستدعاء الخاص بنا.

العناصر

يحتاج هذا الخطاف إلى الإستدعاء للتشغيل بعد تغيير كل حالة ، والتبعيات التي يجب مراقبتها ، وخيار واضح إذا احتجنا إلى مسح Queries غير الضرورية.

بدء بناء الخطاف الثاني

const useNextQueryEffect = (cb, deps, clear) => {
  const { queries, addQueries, clearQueries } = useNextQuery({}, true);
  ...
};

بالتأكيد لن نعيد كتابة كل شيء ، سنستخدم الخطاف السابق وطرقه لإدارة Query.

الهدف الأول الذي أردنا تحقيقه من خلال هذا الخطاف هو الاستماع إلى التبعيات ، لذلك سنستخدم useEffect مرة أخرى.

useEffect(() => {
  ...
}, deps);

يجب أن يكون استدعاء في useEffect لأننا نحتاج إلى استعادة قيمته المُعادة في كل مرة تتغير فيها الحالة ، قلت القيمة المُعادة وليس رد النداء نفسه ، لذلك سنقوم بتمرير قيمته المُعادة إلى addQueries. وبالتالي:

useEffect(() => {
  addQueries(cb());
}, deps);

الآن أعتقد أن لدينا خطافًا جيدًا ، لكنني أشعر أن هناك شيئًا ما فاتني ، نعم ، مثل الحالة السابقة لـ setState ، أحتاج إلى Query السابق.

بالنسبة للمعامل الثالث (خيار مسح) ، أحتاج فقط إلى طريقة clearQueries من الخطاف السابق.

useEffect(() => {
 const prevQueries = queries;
 if (clear) {
   clearQueries();
 }
 addQueries(cb(prevQueries));
}, deps);

أضع Queries السابقة قبل الشرط الواضح – كما تعلم لا يمكننا وضعه بعد ذلك – لأن الخيار الواضح أحيانًا يمسح Query ويكون prevQueries مكونًا فارغًا.

نعم، هذا كل شيء.

لقد عانيت دائمًا من مثل هذه المشكلات ، وقد صنعت حزمة من واحدة منهم مرة واحدة ، لذلك إذا كنت تريد إنشاء حزمة npm من هذه الفكرة ، فلا مشكلة ، سأكون أول من يستخدمها.

محمدباقر عبيات

The one Who loves solving stuff and writing about them.

منشور ذات صلة

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *

السلة