说明: 我正在开发一个 React 项目,在该项目中,即使用户注销后,我也需要保留用户之前所在的路线,而不使用 localStorage。我使用 React Router v6 和 Apollo Client 进行状态管理和 GraphQL 查询。目前,当用户注销时,之前的路由将重置为默认值(“/”),而不是保留上次访问的路由。
问题: 当用户注销时, previousRouteRef 会重置为默认值(“/”),我需要它来保留上次访问的路由。
预期行为: 我期望 previousRouteRef.current 保存最后访问的路由并在用户注销后保持不变。这样,当用户重新登录时,我可以使用存储的路由将他们重定向回注销之前的位置。
观察结果: 我注意到 RoutesWrapper 组件在注销过程中重新渲染了 3 次。我怀疑这种重复渲染可能会导致 previousRouteRef 重置为其默认值(“/”),而不是保留上次访问的路线。
渲染计数: 我添加了一个计数器来跟踪 RoutesWrapper 渲染的次数,并在每次渲染期间记录 previousRouteRef 的值。日志确认 previousRouteRef.current 在重新渲染后重置为默认路由路径。
涉及文件: RoutesWrapper.js 该组件管理路由并检查用户是否登录。它包含 previousRouteRef,应该保留最后访问的路由。
import { useEffect, useRef, useState } from "react";
import LineWobbleLoader from "@/components/customs/helpers/page-loader";
import useAuthRedirect from "@/hooks/use-auth-redirect";
import MainLayout from "@/layout/main-layout";
import PageLayout from "@/layout/page-layout";
import ForgotPassword from "@/pages/auth-form/login/forgot-password-page";
import { Login } from "@/pages/auth-form/login/login";
import ResetPassword from "@/pages/auth-form/login/reset-password";
import { SignUp } from "@/pages/auth-form/signup/signup";
import SignUpVerify from "@/pages/auth-form/signup/signup-verify";
import AddContact from "@/pages/contacts/add-contact";
import Contacts from "@/pages/contacts/contacts";
import Dashboard from "@/pages/dashboard/dashboard";
import MessageTemplate from "@/pages/messages/message-templates";
import SetupPage from "@/pages/setup/setup-page";
import SuccessPage from "@/pages/success/success-page";
import CreateTemplate from "@/pages/templates/add-template";
import { Navigate, Route, Routes } from "react-router-dom";
function RoutesWrapper() {
const [isLoggedIn, setIsLoggedIn] = useState<boolean>(false);
const previousRouteRef = useRef<string>("/");
const renderCount = useRef(0);
const { meData, whatsappData, meLoading, whatsappLoading, refetchMe } =
useAuthRedirect({ isLoggedIn });
renderCount.current += 1;
console.log(`RoutesWrapper render count: ${renderCount.current}`);
useEffect(() => {
refetchMe();
}, [isLoggedIn, refetchMe]);
if (meLoading || whatsappLoading) {
return (
<div className="h-screen flex justify-center items-center">
<LineWobbleLoader />
</div>
);
}
return (
<Routes>
{!meData ? (
<>
<Route path="/" element={<Login setIsLoggedIn={setIsLoggedIn} previousRouteRef={previousRouteRef} />} />
<Route path="/signup" element={<SignUp />} />
<Route path="/forgot-password" element={<ForgotPassword />} />
<Route path="/reset-password" element={<ResetPassword />} />
<Route path="/success-page" element={<SuccessPage />} />
</>
) : (
<>
<Route path="/" element={whatsappData?.getWhatsApp?.business ? <Navigate to="/contacts" replace /> : <Navigate to="/setup" replace />} />
<Route path="/setup" element={<SetupPage setIsLoggedIn={setIsLoggedIn} previousRouteRef={previousRouteRef} />} />
<Route element={<PageLayout />}>
{whatsappData?.getWhatsApp?.business ? (
<Route element={<MainLayout previousRouteRef={previousRouteRef} meData={meData.me} setIsLoggedIn={setIsLoggedIn} />}>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/contacts" element={<Contacts />} />
<Route path="/addcontact" element={<AddContact />} />
<Route path="/templates" element={<CreateTemplate />} />
<Route path="/newtemplate" element={<MessageTemplate />} />
<Route path="*" element={<Navigate to="/" replace />} />
</Route>
) : (
<Route path="*" element={<Navigate to="/setup" replace />} />
)}
</Route>
</>
)}
</Routes>
);
}
export default RoutesWrapper;
useLogout.js 该挂钩处理注销过程,并应在注销之前将 previousRouteRef 设置为当前路径名。
import { useMutation } from "@apollo/client";
import { LOGOUT } from "@/services/gpl/mutations";
const useLogout = ({ setIsLoggedIn, previousRouteRef }) => {
const [logout] = useMutation(LOGOUT);
const handleLogout = () => {
previousRouteRef.current = window.location.pathname; // Persisting the current route
logout()
.then(() => {
setIsLoggedIn(false);
window.location.href = "/";
})
.catch(error => {
console.error("Logout error:", error);
});
};
return { handleLogout };
};
export default useLogout;
使用登录.tsx
import { useLazyQuery, useApolloClient } from "@apollo/client";
import { LOGIN, ME } from "@/services/gpl/queries";
import { useToast } from "@/components/ui/use-toast";
import { useNavigate } from "react-router-dom";
interface LoginInput {
email: string;
password: string;
}
type Props = {
setIsLoggedIn: React.Dispatch<React.SetStateAction<boolean>>;
previousRouteRef: React.MutableRefObject<string>;
};
const useLogin = ({ setIsLoggedIn, previousRouteRef }: Props) => {
const { toast } = useToast();
const navigate = useNavigate();
const client = useApolloClient();
const [login, { loading, error, data }] = useLazyQuery(LOGIN);
const handleLogin = (loginInput: LoginInput) => {
login({ variables: { login: loginInput } })
.then((response) => {
if (response.data?.login) {
setIsLoggedIn(true);
const cachedMeData = client.readQuery({ query: ME });
if (cachedMeData && cachedMeData.me) {
if (cachedMeData.me.email === response.data.login.email) {
navigate(previousRouteRef.current || "/contacts");
return;
}
}
navigate("/contacts");
} else {
toast({
title: "Failed",
description: error?.message,
className: "text-red-600 border-red-600",
});
}
})
.catch((error) => {
console.log(error);
toast({
description: "Invalid email or password",
className: "text-red-600 border-red-600",
});
});
};
return {
loading,
error,
data,
handleLogin,
};
};
export default useLogin;
我尝试过的: 使用 useRef 作为 previousRouteRef:我使用 useRef 初始化了 previousRouteRef,以存储注销前最后访问的路由。但是,注销后,该值将重置为默认值(“/”)而不是保留。 在handleLogout中设置previousRouteRef:我尝试在handleLogout函数中注销之前将previousRouteRef.current设置为window.location.pathname。尽管如此,该值仍然重置为默认路由。 调试渲染计数:我添加了控制台日志来跟踪 RoutesWrapper 组件的渲染计数和 previousRouteRef 的值。我观察到该组件在注销过程中多次重新渲染,这可能会影响状态。
如果您真的想“保留”以前访问的路由 URL,您可能应该使用 localStorage,但我看到的问题是在您的注销处理程序中,您在其中执行硬重定向回
"/"
,即 window.location.href = "/";
,这必然是重新加载页面,从而重新安装整个 React 应用程序。 previousRouteRef
将被初始化为 "/"
。
我建议使用
useNavigate
钩子并发出客户端重定向回主页。
示例:
import { useLocation, useNavigate } from "react-router-dom";
import { useMutation } from "@apollo/client";
import { LOGOUT } from "@/services/gpl/mutations";
const useLogout = ({ setIsLoggedIn, previousRouteRef }) => {
const { pathname } = useLocation();
const navigate = useNavigate();
const [logout] = useMutation(LOGOUT);
const handleLogout = async () => {
previousRouteRef.current = pathname; // Persisting the current route
try {
await logout();
setIsLoggedIn(false);
navigate("/", { replace: true });
} catch (error) {
console.error("Logout error:", error);
};
};
return { handleLogout };
};
export default useLogout;
这应该保持应用程序已安装并且不会重置
previousRouteRef
值。