تنظیمات 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 بزنیم، به آن نیاز پیدا می کنیم.