You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.23 12:17:45