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

登录后React NavBar未自动刷新:路由跳转不更新仅刷新页面生效

问题描述

登录成功后通过navigate跳转到/home页面,NavBar组件并未自动更新,仍显示未登录状态的导航链接,仅手动刷新页面后,才会渲染登录后的导航内容。

相关代码

App组件

function App() {
  const [token, setToken] = useState();

  useEffect(() => {
    const auth = localStorage.getItem('auth_token');
    setToken(auth);
  }, [token]);

  return (
    <div>
      <FullNavBar />
      <Routes>
        <Route path='/login' element={<Login />}></Route>
        <Route path='/register' element={<Register />}></Route>
        <Route path='/forgot_password' element={<ForgotPassword />}></Route>
        <Route element={<ProtectedRoutes />}>
          <Route path='/home' element={<Home />}></Route>
          <Route path='/active_lottery' element={<Activelottery />}></Route>
        </Route>
      </Routes>
    </div>
  );
}

export default App;

受保护路由组件

import { Navigate, Outlet } from 'react-router';

const authorization = () => {
  const token = localStorage.getItem('auth_token');
  return token ? true : false;
};

const ProtectedRoutes = () => {
  const isAuth = authorization();
  return isAuth ? <Outlet /> : <Navigate to='/login' />;
};

export default ProtectedRoutes;

登录跳转逻辑

const onSubmitHandler = async (event) => {
  event.preventDefault();
  await axios
    .post(
      'url/dev/user/login',
      loginForm,
    )
    .then((response) => {
      localStorage.setItem(
        'auth_token',
        response.data.AuthenticationResult.AccessToken,
      );
      toast.success('Your in now');
      setTimeout(() => {
        navigate('/home');
      }, 1000);
    })
    .catch((err) => {
      console.log(err);
      toast.error(err.response.data.message);
    });
};

FullNavBar组件

export default function FullNavBar() {
  const [menuOpen, setMenuOpen] = useState(false);
  const [auth, setAuth] = useState(false);

  const token = localStorage.getItem('auth_token');

  useEffect(() => {
    if (token) {
      console.log(token);
      setAuth(true);
    }
  }, [auth]);

  return (
    <div className="bg-gradient-to-r from-yellow-400 to-yellow-500">
      <Navbar token={auth} menuOpen={menuOpen} setMenuOpen={setMenuOpen} />
      {menuOpen && <MobileMenu>{navLinks(auth)}</MobileMenu>}
    </div>
  );
}

const navLinks = token => {
  let pages = ['About', 'Contact', 'Login'];

  if (token) {
    pages = ['Buy', 'Tickets', 'History', 'Profile'];
  }

  return pages.map(page =>
    page === 'Profile' ? (
      <button key={page} className="inline-block">
        {' '}
        <img
          className="rounded-full w-11 h-11"
          src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQhumf_G7azRo-qCcnB533PPwZx386EK1cozzMAMEtW3A&s"
        ></img>
      </button>
    ) : page === 'Tickets' ? (
      <a
        key={page}
        className="no-underline text-gray-800 font-semibold hover:text-gray-500 relative bottom-4"
        href={`${page.toLowerCase()}`}
      >
        100 {page}
      </a>
    ) : (
      <a
        key={page}
        className="no-underline text-gray-800 font-semibold hover:text-gray-500 relative bottom-4"
        href={`${page.toLowerCase()}`}
      >
        {page}
      </a>
    ),
  );
};

问题原因

  1. App组件状态未同步:App中的token状态仅在初始化时从localStorage读取一次,登录后localStorage更新但App的token状态未更新,导致FullNavBar没有收到新props触发重渲染。
  2. FullNavBar监听逻辑错误:FullNavBar中的useEffect依赖是auth自身,而非token,且token仅在组件初始化时读取,无法响应localStorage的后续变化。

解决方案

方案一:Props传递+Storage监听(适合小型项目)

1. 修改App组件

让App的token状态响应localStorage变化,并传递给FullNavBar:

function App() {
  const [token, setToken] = useState(localStorage.getItem('auth_token'));

  // 监听localStorage中auth_token的变化
  useEffect(() => {
    const handleStorageUpdate = (e) => {
      if (e.key === 'auth_token') {
        setToken(e.newValue);
      }
    };

    window.addEventListener('storage', handleStorageUpdate);
    return () => window.removeEventListener('storage', handleStorageUpdate);
  }, []);

  return (
    <div>
      <FullNavBar token={token} />
      <Routes>
        {/* 路由配置不变 */}
      </Routes>
    </div>
  );
}

export default App;

2. 修改FullNavBar组件

依赖传入的token更新auth状态:

export default function FullNavBar({ token }) {
  const [menuOpen, setMenuOpen] = useState(false);
  const [auth, setAuth] = useState(!!token);

  useEffect(() => {
    // 当token变化时更新auth状态
    setAuth(!!token);
  }, [token]);

  return (
    <div className="bg-gradient-to-r from-yellow-400 to-yellow-500">
      <Navbar token={auth} menuOpen={menuOpen} setMenuOpen={setMenuOpen} />
      {menuOpen && <MobileMenu>{navLinks(auth)}</MobileMenu>}
    </div>
  );
}

// navLinks函数保持不变

方案二:React Context管理全局状态(更优雅,适合中大型项目)

1. 创建AuthContext

// AuthContext.js
import { createContext, useContext, useState } from 'react';

const AuthContext = createContext();

export function AuthProvider({ children }) {
  const [token, setToken] = useState(localStorage.getItem('auth_token'));

  // 登录时更新token和localStorage
  const login = (newToken) => {
    localStorage.setItem('auth_token', newToken);
    setToken(newToken);
  };

  // 登出时清除token
  const logout = () => {
    localStorage.removeItem('auth_token');
    setToken(null);
  };

  return (
    <AuthContext.Provider value={{ token, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
}

// 自定义hooks方便组件使用
export function useAuth() {
  return useContext(AuthContext);
}

2. 修改App组件,用AuthProvider包裹

import { AuthProvider } from './AuthContext';

function App() {
  return (
    <AuthProvider>
      <div>
        <FullNavBar />
        <Routes>
          {/* 路由配置不变 */}
        </Routes>
      </div>
    </AuthProvider>
  );
}

export default App;

3. 修改Login组件的登录逻辑

调用Context中的login方法更新全局状态:

import { useAuth } from './AuthContext';
import { useNavigate } from 'react-router-dom';

const Login = () => {
  const { login } = useAuth();
  const navigate = useNavigate();

  const onSubmitHandler = async (event) => {
    event.preventDefault();
    await axios
      .post('url/dev/user/login', loginForm)
      .then((response) => {
        const accessToken = response.data.AuthenticationResult.AccessToken;
        login(accessToken); // 更新全局登录状态
        toast.success('Your in now');
        setTimeout(() => {
          navigate('/home');
        }, 1000);
      })
      .catch((err) => {
        console.log(err);
        toast.error(err.response.data.message);
      });
  };

  // 其他组件逻辑
};

4. 修改FullNavBar组件,使用useAuth获取状态

import { useAuth } from './AuthContext';

export default function FullNavBar() {
  const { token } = useAuth();
  const [menuOpen, setMenuOpen] = useState(false);
  const auth = !!token; // 直接根据token判断登录状态

  return (
    <div className="bg-gradient-to-r from-yellow-400 to-yellow-500">
      <Navbar token={auth} menuOpen={menuOpen} setMenuOpen={setMenuOpen} />
      {menuOpen && <MobileMenu>{navLinks(auth)}</MobileMenu>}
    </div>
  );
}

// navLinks函数保持不变

内容的提问来源于stack exchange,提问作者Hulubina

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 12:10:58