Remix中实现嵌套路由父路由不可访问并默认跳转至子路由的方案
Remix中实现嵌套路由父路由不可访问并默认跳转至子路由的方案
我来帮你搞定这个需求!在Remix里实现父路由不可访问、默认跳转到子路由的效果,其实有更贴合框架最佳实践的方法,比你自己写钩子要更可靠,我一步步给你讲:
1. 用Loader实现服务端重定向(推荐方案)
Remix的Loader函数是在服务端执行的,用它来做重定向不仅不会出现页面闪现的问题,还能直接拦截用户对/users/123这类父路由的访问,是最优解。
你只需要在$userId.tsx里导出一个Loader函数,获取当前的userId参数,然后直接重定向到对应的about子路由即可:
import { redirect, LoaderFunctionArgs, useParams } from "@remix-run/react"; import { NavLink, Outlet } from "@remix-run/react"; // 服务端重定向,拦截父路由访问 export async function loader({ params }: LoaderFunctionArgs) { const { userId } = params; // 直接重定向到about子路由 return redirect(`/users/${userId}/about`); } export default function UserLayout() { const { userId } = useParams(); // 这里保留你原有的布局代码(用户名称、头像等) return ( <div> <nav className="my-8"> <ul className="flex border-b-custom-semigrey border-b"> <li> <NavLink to={`/users/${userId}/about`} {/* 改成动态路径 */} activeClass="text-custom-black border-b-custom-black border-b-2 rounded-t" inactiveClass="text-custom-grey" defaultClass="font-semibold text-base font-inter hover:text-custom-black mr-4 pb-3" preventScrollReset={true} > About </NavLink> </li> <li> <NavLink to={`/users/${userId}/feedback`} {/* 改成动态路径 */} activeClass="text-custom-black border-b-custom-black border-b-2 rounded-t" inactiveClass="text-custom-grey" defaultClass="font-semibold text-base font-inter hover:text-custom-black mx-4 pb-3" preventScrollReset={true} > Feedback </NavLink> </li> </ul> </nav> <main> <Outlet /> </main> </div> ); }
2. 修正NavLink的动态路径
你之前的代码里把to属性写死成了/user/123/about,这会导致所有用户都跳转到ID为123的页面,显然不对。我上面的代码里已经改成了用useParams()获取当前的userId,动态生成路由路径,这样每个用户都会跳转到自己的子路由。
3. (可选)如果一定要用客户端钩子的话
如果你因为某些原因必须用客户端钩子来实现,那你之前写的useRedirect有几个问题需要修正:
- 判断条件错误:
paths.map((path) => location.pathname === path)返回的是布尔值数组,不是单个布尔值,应该用paths.includes(location.pathname) - useEffect的依赖项不全:需要加上
location和navigate,不然路由变化时不会触发 - 要加上空数组判断,避免
userId为空的情况
修正后的钩子代码:
import { useNavigate, useLocation, useEffect } from "@remix-run/react"; export function useRedirect(paths: string[], navigationPath: string) { const navigate = useNavigate(); const location = useLocation(); useEffect(() => { // 确保导航路径有效,且当前路径在需要重定向的列表里 if (navigationPath && paths.includes(location.pathname)) { navigate(navigationPath); } }, [location, navigate, paths, navigationPath]); // 加上所有依赖项 }
然后在UserLayout里使用:
const { userId } = useParams(); useRedirect([`/users/${userId}`], `/users/${userId}/about`);
不过还是强烈推荐用Loader的方案,因为服务端重定向更符合Remix的设计理念,性能和体验都更好。
备注:内容来源于stack exchange,提问作者Oliver Darby
相关产品推荐
相关产品推荐

