Next 13 (App router)當異動 SearchParam(queryString) 後,局部更新相關組件
前言
在 Nextjs 13(App router) 中,想要觸發 Rerender,但又想要保有現有的Client State
Nextjs 13 router 增加了新功能 refresh()
,即 router.refresh()
。就不會造成整個頁面重新整理,並觸發 Server Component re-fetch API, 之後向下更新後有變化的組件
以下舉例二個常見的使用情境
PS: 下述範例所指的 router 皆來自 next/navigation
,如下
import { useRouter } from 'next/navigation';
router = useRouter();
發送 API 增加、更新內容後,rerender 畫面。而取得畫面所有資料的 API 是寫在 Server Component
由於資料來源是寫在 Server Component,就無法像以前一樣很簡單地觸發新的查詢
當 Post api 完成後,Call router.refresh()
,可以做到重新打 API (Re-fetch) 並將資料一路向下,Rerender 有變化的組件,而非所有頁面
搜尋功能,會將各種欄位放在 searchParam(queryString) 以方便 User帶連結直接查看結果
比如/search?product=tshirt&size=m
,對於搜尋頁面,這是一個很常見的情境
在 App router 中,會發現直接用 router.refresh()
並不會觸發 Rerender,因為組件資料從 Server 流下來,Next 本身的 Cache 機制並不會拿到最新的 searchParams,導致router.refresh()
執行後,畫面沒有變化
解決方法是搭配router.push()
與router.refresh()
,雖然會讓History 多一頁面
對 User 來說也是合理的情境:可以回遡之前的搜尋記錄
直接封裝成 hook,方便使用!
function useSetParamAndPush() {
const router = useRouter();
const searchParams = useSearchParams();
const pathname = usePathname();
return (param: string, value: string) => {
const current = new URLSearchParams(Array.from(searchParams?.entries() || [])); // -> has to use this form
current.set(param, value);
router.push(`/${pathname}?${current.toString()}`);
router.refresh();
};
}
用法
const setParamAndPush = useSetParamAndPush();
return <div onClick={() => setParamAndPush('size', 'M')}>測試</Tag>