شیوه صحیح watch زدن روی تغییرات query در nuxtjs

شیوه صحیح watch زدن روی تغییرات query در nuxtjs

گاهی در پیاده سازی صفحات در وب اپلیکیشن نیاز هست که طوری صفحه را طراحی کنیم که کاربر به راحتی بتواند با اشتراک گذاری لینک، به همان اطلاعات دست پیدا کند، بنابراین استفاده از queryString یک روال معمول در پیاده سازی فیلترهای مربوط به یک صفحه است، در این مقاله روش درست watch زدن روی تغییرات query را آموزش می دهیم. ابتدا تنظیماتی انجام می دهیم که داده queryString را در nuxtjs به فرمت براکت در بیاوریم و سپس اقدام به پیاده سازی composable خود می کنیم.

یدالله ضیاالدینی
جمعه ۰۸-دی-۱۴۰۲

تنظیمات routing در nuxt

اول پکیج qs را با دستور npm install qs نصب کنید، از این پکیج برای فرمت کردن داده ها بصورت براکت استفاده می کنیم.

یک دایرکتوری به اسم app داخل پروژه ایجاد کنید و router.options.ts را داخل آن ایجاد کنید. (اگر از typescript استفاده نمی کنید می توانید فرمت آن را به js تغییر دهید.)

import type { RouterConfig } from "@nuxt/schema";
import qs from "qs";

export default <RouterConfig>{
  parseQuery(query: any) {
    return qs.parse(query,{ arrayFormat: 'brackets', parseArrays: false });
  },
  stringifyQuery(query: any) {
    const result = qs.stringify(query,{ arrayFormat: 'brackets' });
    return result ? result : "";
  },
};

یک watch ساده روی کوئری

export const useWatchQuery=(onChange:Function)=>{
  const route=useRoute();
  watch(()=>route.query,(value,oldValue)=>{
   onChange(value,oldValue);
  },{deep:true})
}

دلیل استفاده از deep در کد بالا این هست که تغییرات مقادیر تودرتو هم توسط watch شناسایی شود، اما...

از آنجایی که object ها در جاوااسکریپت byReference هستند، ممکن است مقدار تغییر نکند و فقط آدرس object در حافظه تغییر کند، که در این صورت ما می خواهیم تغییرات را نادیده بگیریم و فقط در صورتی که یکی از مقادیر تغییر کرده onChange را صدا بزنیم.

حل مشکل مرحله قبل
export const useWatchQuery=(onChange:Function)=>{
  const route=useRoute();
  watch(()=>route.query,(value,oldValue)=>{
    if(JSON.stringify(value)!=JSON.stringify(oldValue)){
      onChange(value,oldValue);
    }
  },{deep:true})
}

ما در اینجا از JSON.stringify استفاده کردیم، چون یک روش ساده و دم دستی بود، اما خب باید بدانید که اگر object طولانی باشد، این روش مقایسه بهینه نیست برای بهینه تر انجام دادن این کار می توانید از پکیج lodash equal استفاده کنید.

اضافه کردن ignore

گاهی لازم است که روی یک یا چند کلید خاص از query عملی انجام ندهیم، برای این کار یک آرایه ignore به عنوان config می گیریم و کلیدهایی که پاس داده می شوند را از query پاک می کنیم، دقت کنید که برای حفظ reactivity از computed کمک گرفته ایم.

export const useWatchQuery=(onChange:Function,{ignore}:{ignore:string[]}={ignore:[]})=>{
  const route=useRoute();
  const getQuery=computed(()=>{
    const query={...route.query}
    ignore.forEach((item)=>{
      if(query[item]){
        delete query[item]
      }
    })
    return query;
  })
  watch(getQuery,(value,oldValue)=>{
    if(JSON.stringify(value)!=JSON.stringify(oldValue)){
      onChange(value,oldValue);
    }
  },{deep:true})
}

اضافه کردن debounce

دلیل استفاده از debounce چیست؟ سناریویی را تصور کنید که چند چک باکس برای فیلتر مثلا برند کالاها قرار داده ایم، و قرار است وقتی که query تغییر می کند، به سرور درخواست بزنیم تا داده های فیلتر شده را دریافت کنیم، در چنین حالتی اگر کاربر پشت سرهم چند چک باکس را با سرعت زیاد تغییر دهد و بنا باشد که با هر تغییر کوئری به سرور درخواست بزنیم، تعداد درخواست ها زیاد می شود و زیاد بهینه نیست، برای این منظور debounce را اضافه می کنیم.

اول با دستور npm install @vueuse/core پکیج کمکی را نصب می کنیم.

import { watchDebounced } from '@vueuse/core'
export const useWatchQuery=(onChange:Function,config:{ignore:string[],debounce:number}={ignore:[],debounce:200})=>{
  const route=useRoute();
  const getQuery=computed(()=>{
    const query={...route.query}
    config.ignore.forEach((item)=>{
      if(query[item]){
        delete query[item]
      }
    })
    return query;
  })
  watchDebounced(getQuery,(value,oldValue)=>{
    if(JSON.stringify(value)!=JSON.stringify(oldValue)){
      onChange(value,oldValue);
    }
  },{debounce:config.debounce, deep:true})
}

تمرین

سعی کنید یک config دیگر به جز ignore اضافه کنید که وقتی نیاز داریم، فقط روی چند کلید خاص از کوئری watch بزنیم، به آن نیاز پیدا می کنیم.

کلیه حقوق این وب سایت متعلق به آکادمی لند می باشد و هرگونه کپی برداری از محصولات غیر مجاز می باشد.
box iconbox iconارتباط با ماتصویر نماد