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

React/Strapi应用登录后useNavigate致Auth未持久化到LocalStorage

问题:React/Strapi认证登录后跳转导致LocalStorage未写入的问题

我正在重构React/Strapi Web应用的认证模块,应用内部分内容需登录后才可访问。登录逻辑为向Strapi后端提交凭证,将返回的JWT存储至LocalStorage。我编写了useAuth自定义Hook负责认证状态的设置、持久化与提供,它会检查本地是否存储了auth对象,存在则返回,否则初始化状态,该Hook被登录表单组件调用。

当前问题:登录成功后使用react-router-dom的useNavigate钩子跳转到/dashboard页面时,出现以下情况:

  • 页面刷新
  • Auth数据未写入LocalStorage
  • 用户无法访问受保护内容
  • 登录表单被清空

若注释掉navigate("/dashboard")语句,Auth可正确写入LocalStorage,用户停留在登录页(表单清空)且能正常访问受保护页面。怀疑是useNavigate使用错误,或与useAuth Hook存在未考虑的交互。


useAuth Hook代码

import { useEffect, useState } from "react";

const AUTH_STORAGE_KEY = "my-app-auth";

export const useAuth = () => {
  const [auth, setAuth] = useState(() => {
    try {
      const storedAuth = localStorage.getItem(AUTH_STORAGE_KEY);
      return storedAuth ? JSON.parse(storedAuth) : { user: null, accessToken: null };
    } catch (error) {
      console.error("Error parsing stored auth:", error);
      return { user: null, accessToken: null };
    }
  });

  useAuthPersistence(auth);

  return { auth, setAuth };
};

export const useAuthPersistence = (auth) => {
  useEffect(() => {
    try {
      if (auth.accessToken) {
        localStorage.setItem(AUTH_STORAGE_KEY, JSON.stringify(auth));
      } else {
        localStorage.removeItem(AUTH_STORAGE_KEY);
      }
    } catch (error) {
      console.error("Error persisting auth:", error);
    }
  }, [auth, AUTH_STORAGE_KEY]);
};

登录表单组件相关代码

import React, { useRef, useState, useEffect } from 'react';
import { Link, useNavigate } from 'react-router-dom';

import { useAuth } from '../../hooks/useAuth.js';

export function SignInForm () {
    const userRef = useRef(); 
    const { setAuth } = useAuth();
    const navigate = useNavigate();

    // [部分代码省略]

    const handleSubmit = async (e) => {
            
    // [部分代码省略]

            if(response.ok) {
                const data = await response.json();           
                const user = data.user;
                const accessToken = data.jwt;

                console.log(user)
                console.log(accessToken)

                // Store the user and access token in the local storage
                setAuth({ user, accessToken });

                // Navigate to the dashboard
                navigate("/dashboard"); 

            } else if (response.status === 400) {
                // [部分代码省略]
}

问题原因与解决方案

核心原因

  1. setAuth是React异步状态更新函数,调用后立刻执行navigate会导致状态还未更新完成,useAuthPersistence的useEffect还没触发写入LocalStorage,新页面加载时读取不到认证数据。
  2. 表单提交未阻止默认行为,导致浏览器发起传统同步提交,直接刷新页面,状态来不及持久化就被重置。

解决步骤

  1. 阻止表单默认提交行为
    在handleSubmit开头添加代码,避免页面刷新:

    const handleSubmit = async (e) => {
      e.preventDefault(); // 阻止浏览器默认表单提交
      // 原有请求逻辑...
    };
    
  2. 等待状态更新完成后再跳转
    通过useEffect监听auth状态变化,确认accessToken存在后再执行跳转:

    export function SignInForm () {
      const userRef = useRef(); 
      const { auth, setAuth } = useAuth(); // 新增auth状态引用
      const navigate = useNavigate();
    
      // 监听auth状态,认证成功后跳转
      useEffect(() => {
        if (auth.accessToken) {
          navigate("/dashboard");
        }
      }, [auth, navigate]);
    
      const handleSubmit = async (e) => {
        e.preventDefault();
        // 原有请求逻辑...
        if(response.ok) {
          const data = await response.json();           
          const user = data.user;
          const accessToken = data.jwt;
    
          setAuth({ user, accessToken });
          // 移除原有直接调用的navigate
        }
        // 错误处理逻辑...
      };
    
      // 其他组件代码...
    }
    
  3. 优化useAuthPersistence依赖项
    移除常量AUTH_STORAGE_KEY的依赖,避免不必要的useEffect触发:

    export const useAuthPersistence = (auth) => {
      useEffect(() => {
        try {
          if (auth.accessToken) {
            localStorage.setItem(AUTH_STORAGE_KEY, JSON.stringify(auth));
          } else {
            localStorage.removeItem(AUTH_STORAGE_KEY);
          }
        } catch (error) {
          console.error("Error persisting auth:", error);
        }
      }, [auth]); // 移除AUTH_STORAGE_KEY
    };
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 19:57:52