在 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 状态是什么样的,但你会希望将初始值设置为“不确定”值,也就是说,一个既不正确的值或假的。 undefined
或 null
是不错的候选人。
从这里开始,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>
)
}
]
}
];
我目前正在使用 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 状态是什么样的,但你会希望将初始值设置为“不确定”值,也就是说,一个既不正确的值或假的。 undefined
或 null
是不错的候选人。
从这里开始,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>
)
}
]
}
];