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

React登录页useAuth钩子authenticated值反复切换问题求助

React登录页面Auth钩子状态异常:authenticated值反复切换

我用React开发登录页面时,在创建Context和认证钩子useAuth时遇到问题:authenticated的值无法保持为true,会在true和false之间交替切换,排查后没发现循环等异常情况。

相关代码如下:

import backend from "../utils/backend";

import { useState, useEffect } from "react";

export default function useAuth() {
  const [authenticated, setAuthenticated] = useState(false);

  useEffect(() => {
    console.log(authenticated);

    const token = localStorage.getItem("token");

    if (token && !authenticated) {
      authUser(token);
    }
  }, []);

  setInterval(() => {
    console.log(authenticated);
  }, 300);

  async function authUser(token) {
    backend.defaults.headers.Authorization = `Bearer ${JSON.parse(token)}`;

    try {
      const data = await backend.get("/users/verify").then((res) => {
        return res.data;
      });
      console.log(data, "response from back-end");
      setAuthenticated(data);
    } catch (error) {
      console.log(error);
    }
  }

  return { authenticated };
}

控制台输出显示authenticated在true和false之间交替变化。我试过重构系统、直接在authUser里调用setAuthenticated(true),都没解决问题。


问题分析

  • 闭包与定时器残留:钩子每次渲染都会创建新的setInterval,旧定时器未被清理,且每个定时器捕获的是创建时的authenticated闭包值,多个定时器同时输出不同状态值,造成“状态切换”的假象。
  • useEffect依赖缺失:useEffect依赖数组为空,内部始终引用初始的authenticated值(false),若钩子重复执行(比如Provider包裹的组件重渲染),会重复触发authUser请求,可能导致状态反复更新。
  • 无请求防重复机制:没有加载状态控制,可能多次调用authUser,引发多次状态更新。

解决方案

修改后的代码如下:

import backend from "../utils/backend";
import { useState, useEffect, useCallback } from "react";

export default function useAuth() {
  const [authenticated, setAuthenticated] = useState(false);
  const [isLoading, setIsLoading] = useState(true);

  // 用useCallback稳定函数引用,避免重复创建
  const authUser = useCallback(async (token) => {
    setIsLoading(true);
    backend.defaults.headers.Authorization = `Bearer ${JSON.parse(token)}`;
    try {
      const res = await backend.get("/users/verify");
      const data = res.data;
      console.log(data, "response from back-end");
      setAuthenticated(data);
    } catch (error) {
      console.log(error);
      setAuthenticated(false);
    } finally {
      setIsLoading(false);
    }
  }, []);

  useEffect(() => {
    const token = localStorage.getItem("token");
    // 仅在有token、未认证且未加载时触发请求
    if (token && !authenticated && !isLoading) {
      authUser(token);
    }
  }, [authenticated, isLoading, authUser]);

  useEffect(() => {
    // 定时器放入useEffect,监听authenticated确保捕获最新状态
    const interval = setInterval(() => {
      console.log(authenticated);
    }, 300);
    // 卸载时清理定时器,避免残留
    return () => clearInterval(interval);
  }, [authenticated]);

  return { authenticated, isLoading };
}

关键修改说明:

  • 用useCallback包裹authUser,稳定函数引用,作为useEffect依赖避免无效触发。
  • 新增isLoading状态,防止重复发起认证请求。
  • 将定时器移入useEffect并添加清理函数,确保仅存在一个定时器,且始终捕获最新的authenticated值。
  • 补全useEffect依赖数组,确保状态更新后逻辑能正确执行。

内容的提问来源于stack exchange,提问作者Giovanni Carvalho de Oliveira

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 23:10:43