使用 nextjs 12(页面路由器),从“next/router”返回的路由器具有您可以侦听和适当处理的导航事件。 这里是文档。
一个具体事件是
routeChangeStart
。当您希望在用户离开页面之前提示他们时,您已侦听该事件,然后打开模式并抛出错误以阻止导航。
使用 nextjs 13(应用程序路由器),从“next/navigation”返回的路由器不具有订阅事件的相同能力。
文档中有一个解决方案可以告知路线何时已更改。它使用了两个新的钩子
usePathname
useSearchParams
这就是解决方案。
我想知道之前路线即将改变。
您如何知道 nextjs 13 应用程序(使用应用程序路由器)何时将要导航,以及如何阻止它这样做?
如果您使用 Link 组件进行导航,则可以使用自定义组件切换它并使用 useRouter 钩子。
为了在发生之前检测导航事件,我在
NavigationEvents
中使用钩子 usePathname + useRef + useEffect (来自 Nextjs13 的链接)
我的下面的代码正在检查用户是否导航关闭
/about
export function NavigationEvents() {
// Get the current pathname from the router
const pathname = usePathname()
// Create a ref to store the previous pathname
const ref = useRef(pathname)
useEffect(() => {
// Check if the pathname has changed and if the previous pathname was '/page'
if (ref.current !== pathname &&
ref.current === '/about') {
// Do something before the page changes
// For example, you could show a confirmation dialog or save some data
}
// Update the ref to store the current pathname
ref.current = pathname
}, [pathname])
// Return null because this component doesn't render any UI elements
return null
}
注意:必须将
NavigationEvents
添加到根布局才能正常工作(不是子页面布局)
感谢 Steven Linn (github)
注意:这只是问题第一部分的解决方案。那就是“你怎么知道 nextjs 13 应用程序(使用应用程序路由器)何时将要导航?” 我不相信这个解决方案可以用来防止导航离开。此外,它不适用于后退和前进按钮。但半解决方案总比没有解决方案好,所以我来了。
我遇到了这个问题,但在下一个 14.1.0 中。我能够在路由更改发生之前监听路由更改的方法是引用 this github 评论。他们建议使用他们的 nextjs13-router-events 包。
但是看到我在下一个 14.1.0 中需要这个,我采取了自己的(类似)步骤。总结一下:
从
RouteChangeProvider
、Link
和 useRouteChange
复制粘贴组件代码。
将所有
import Link from "next/link";
更改为import Link from "path/to/custom/Link";
用
RouteChangeProvider
包装您的应用程序
import { RouteChangeProvider } from './RouteChangeProvider';
...
return (
<RouteChangeProvider>
{children}
</RouteChangeProvider>
)
import useRouteChange from './useRouteChange';
...
export default function Component(props: any) {
...
useRouteChange({
onRouteChangeStart: () => {
console.log('Put code here to run BEFORE route changes');
},
onRouteChangeComplete: () => {
console.log('onComplete 3');
}
});
...
}
Link.tsx
组件中,将 const { onRouteChangeStart } = useRouteChangeContext();
线移至 if (!useLink) return <a href={href} onClick={onClick} {...rest} />;
if (!useLink) return <a href={href} onClick={onClick} {...rest} />;
const { onRouteChangeStart } = useRouteChangeContext();
成为
const { onRouteChangeStart } = useRouteChangeContext();
if (!useLink) return <a href={href} onClick={onClick} {...rest} />;
RouteChangeProvider.tsx
中,将 onRouteChangeComplete
添加到使用它的 useEffect 的依赖项中。useEffect(() => onRouteChangeComplete(), [pathname, searchParams]);
成为
useEffect(() => onRouteChangeComplete(),[pathname, searchParams, onRouteChangeComplete]);
附注最后两个步骤是针对我在创建生产版本时收到的错误和警告的修补程序。
"use client";
import { usePathname, useSearchParams } from "next/navigation";
import { useEffect, useRef } from "react";
import "../../css/loader.css";
export default function Loader() {
const path = usePathname();
const params = useSearchParams();
const loaderRef = useRef(null);
if (loaderRef?.current) {
loaderRef.current.classList.remove("loading-bar-end");
loaderRef.current.classList.add("loading-bar-start");
}
useEffect(() => {
if (loaderRef?.current) {
loaderRef.current.classList.remove("loading-bar-start");
loaderRef.current.classList.add("loading-bar-end");
}
});
return (
<div className="fixed z-[50] top-0 w-full">
<div
ref={loaderRef}
className="z-[50] bg-danger pb-1 rounded-full loading-bar-start"
></div>
</div>
);
}
其实很简单!我认为他们的文档使其成为 有点令人困惑,但是当您使用 Link 时会发生什么 或 useRouter 进行导航,usePathname 捕获的路径 路线没有实际加载路线,所以你可以像 在这里开始加载,然后在 useEffect 中你可以停止 加载(使用 CSS 动画或任何你喜欢的东西)。依赖关系 useEffect 可以是 [path, params (useSearchParams*)] 或 没什么,完全取决于你!类似地,useSearchParams 也是如此!