在 React 中刷新同一页面

Refresh on the same page in React

我目前正在使用 React Router 6,尝试在同一页面上刷新时遇到问题,特别是经过身份验证的详细信息页面(例如 /main:id)。 比如我的路由配置如下

const routes = ({ isLoggedIn }: RoutesProps) => [
  {
    path: '/',
    element: (
      <>
        <Outlet />
      </>
    ),
    children: [
      { index: true, element: !isLoggedIn ? <Login /> : <Navigate to="/main" /> },
      {
        path: '/main',
        element: (
          <>
            <ProtectedRoute>
              <MainPage />
            </ProtectedRoute>
          </>
        ),
      },
      {
        path: '/main/:id',
        element: (
          <ProtectedRoute>
            <DetailPage />
          </ProtectedRoute>
        ),
      },
    ],
  },

当我在 url '/main' 上刷新我的 React 应用程序时,我的登录 redux 状态重置为 false,这会返回到登录组件。在我的登录组件中,一个 ueEffect 挂钩被触发以检索本地存储中的刷新令牌,如果令牌有效,它会刷新令牌并将我的登录 redux 状态设置为 true。这让我可以按预期返回“/main”页面。这一切都很好,符合预期

但是,当我在“/main/:id”上刷新页面时,页面刷新到“/main”而不是'main:id'。我想我知道为什么会发生这种情况 - 当我尝试使用受保护路由组件内的 React Router 的 useLocation 挂钩 console.log 位置时,该位置首先打印 'main:id' 但受保护路由重定向到登录页面作为 redux 登录状态被重置。然后,由于上面设置的路由,登录组件更新导航到 main 的 redux 登录状态。最后,protected route 再次被触发,但是这次 protected route 里面的位置是 'main'.

有什么办法可以解决这个问题吗?任何帮助或建议将不胜感激!

问题很可能是您的 ProtectedRoute 组件正在使用来自 Redux 的初始 isLoggedIn 状态来确定身份验证状态 before useEffect 有机会从 localStorage 读取并更新 redux 状态。

我不知道你的初始 isLoggedIn reducer 状态是什么样的,但你会希望将初始值设置为“不确定”值,也就是说,一个既不正确的值或假的。 undefinednull 是不错的候选人。

从这里开始,ProtectedRoute 组件将需要处理这第三个“不确定”状态,并且不呈现 children 属性或 Navigate 组件重定向。

这是一个示例 ProtectedRoute 组件:

const ProtectedRoute = ({ children }) => {
  const location = useLocation();
  const isLoggedIn = useSelector(isLoggedInSelector);

  if (isLoggedIn === undefined) return "... LOADING ...";

  return isLoggedIn ? (
    children
  ) : (
    <Navigate to="/" replace state={{ from: location }} />
  );
};

当用户已经通过身份验证并且 isLoggedIn 状态 resolves/updates 为真值时,他们当前所在的路由将可访问、返回和呈现。

当用户未通过身份验证时 isLoggedIn 状态 resolves/updates 为 non-undefined 虚假值,当前位置被嗅探并将他们重定向到您的登录路径。位置已传递,因此用户可以被重定向回他们最初尝试访问的路线。

这是一个 运行 codesandbox 演示:

你也可以稍微简化你的 routes 函数,如果没有指定 element 道具,默认情况下会呈现 Outlet

const routes = ({ isLoggedIn }) => [
  {
    path: "/",
    children: [
      {
        index: true,
        element: !isLoggedIn ? <Login /> : <Navigate to="/main" />
      },
      {
        path: "/main",
        element: (
          <ProtectedRoute>
            <MainPage />
          </ProtectedRoute>
        )
      },
      {
        path: "/main/:id",
        element: (
          <ProtectedRoute>
            <DetailPage />
          </ProtectedRoute>
        )
      }
    ]
  }
];