在 < Next 13 (or with appDir disabled), you could do:
const MyComponent = () => {
const router = useRouter();
const toggleStatic = () => {
if (router.query.static) {
router.push(router.pathname, router.pathname, { shallow: true });
} else {
router.push(router.pathname, router.pathname + "?static", { shallow: true });
}
}
return <>
// ...
</>
});
这将执行浅层路由器更新,从而更改位置,但不会将其推送到历史记录或触发页面加载。
现在,启用 appDir 后,您需要从
next/navigation
导入函数。但是docs没有说任何关于使用新路由器进行浅层路由器推送的事情?
我能做的就是这样:
const router = useRouter();
const pathname = usePathname();
const searchParams = useSearchParams();
const toggleStatic = () => {
if (searchParams.get("static")) {
router.push(pathname);
} else {
router.push(pathname + "?static");
}
};
但这会重新加载整个页面。有没有办法使用 Next 13 的 appDir 复制浅层路由器功能?
尝试使用
replace
方法而不是 push
:
const router = useRouter();
const pathname = usePathname();
const searchParams = useSearchParams();
const toggleStatic = () => {
if (searchParams.get("static")) {
router.replace(pathname);
} else {
router.replace(pathname + "?static");
}
};
我编写了一个自定义钩子来解决我的情况:
export function useShallowNavigation(defaultValues: Record<string, unknown> = {}) {
const pathname = usePathname();
const searchParams = useSearchParams();
const [params, setParams] = useState(
Object.entries(defaultValues).reduce((agg, [key, value]) => {
if (!agg[key]) agg[key] = String(value);
return agg;
}, Object.fromEntries(searchParams.entries()))
);
useEffect(() => {
const newUrl = Object.keys(params).length
? `${pathname}?${new URLSearchParams(params).toString()}`
: pathname;
if (newUrl !== window.location.pathname + window.location.search) {
window.history.pushState(
{ ...window.history.state, as: newUrl, url: newUrl },
'',
newUrl
);
}
}, [pathname, params]);
return [params, setParams];
}
关键是在对象状态下处理查询参数,然后从该状态同步url。