Next配置子路由后的登录功能

162 阅读2分钟

前情提要:

nextjs同一个域名下配置子路由 - 掘金 (juejin.cn)

问题描述:

/admin登录的时候 会不导航到admin页面;然后在/admin/login这个路径登录就会导航到admin

before

没有登录的时候,url不会改变,仍然会是/admin 但是内容却是Login页面的内容

/admin页面
"use client";

import OrderForm from "../components/orderForm";
import { Suspense } from "react";
import Layout from "./(logout)/layout";
export default function Home() {
  return (
    <main className={"  w-screen flex-col items-center "}>
      <Suspense>
        <Layout>//这个Layout里面包含了CheckLogin
          <OrderForm />
        </Layout>
      </Suspense>
    </main>
  );
}
//CheckLogin
import React, { useEffect, useState } from "react";
import { checkToken } from "@/utils/token-storage";
import Login from "@/app/login/page";
import { useRouter } from "next/navigation";

const CheckLogin: React.FC<{ children: React.ReactNode }> = (props) => {
  const [isLogin, setIsLogin] = useState(false);
  const [checked, setChecked] = useState(false);
  const navigate = useRouter();

  useEffect(() => {
    const loginStatus = checkToken();
    setIsLogin(loginStatus==0?false:true);
    setChecked(true);
  }, [checkToken()]);
console.log("checkToken()",checkToken())
  if (!checked) {
    return null; // or a loading spinner
  }

  return (
    <>
      {isLogin ? props.children : <Login/>}
    </>
  );
};

export default CheckLogin;

Login组件 当我请求成功,handleNav("/"),仍然在/admin这个页面


  const handleLogin = async () => {
    try {
      const res = await axios.post(`/login`, {
        username: parentFormData?.username?.trim(),
        password: parentFormData?.password?.trim(),
      });
      if (res?.data?.code === 100) {
        setLoginRes(LoginRes.failed);
      } else if (res?.data?.code === 200) {
        setLoginRes(LoginRes.success);
        storeToken(res?.data?.data);
        setTimeout(() => handleNav("/"), 1500);//当我请求成功,handleNav("/"),仍然在/admin这个页面
      }
    } catch (err) {}
  };
export const checkToken = () => {
    let token = typeof window && getToken()
    const now = new Date().getTime() / 1000
    const expire = getExpire()
    console.log(now, expire,token)//expire token即使在登录成功后,在也是null
    if (!token || !expire || now >= +expire) return 0
    return 1
}

但是刷新之后就可以正常进入系统 因为在登录之后在localstorage设置了token 再跳转到/admin 但是因为/admin状态都没有改变,checkToken()不会被重新调,所以就还是渲染Login组件

解决方法1

用导航的方式导航到login组件 这样子,在login页面登录成功就会跳转到/admin,重新挂载admin页面,就会再次调用checkToken,得到的就是1了

after

 // admin
  const navigate = useRouter();

  useEffect(() => {
    const loginStatus = checkToken();
    setIsLogin(loginStatus==0?false:true);
    setChecked(true);
  }, []);

  return (
    <>
      {isLogin ? props.children :navigate.push("/login")}
    </>
  );
};

解决方法2

使用Redux toolkit或其他状态管理,在Login组件登录成功的时候就dispatch状态,在admin页面监听这个状态