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

React异步状态异常:Context中isAuth设为true但组件内仍为false

React Context异步状态更新不触发组件权限校验的问题解决

问题根源

  1. ProjectTable组件的useEffect未监听isAuth变化:你的useEffect依赖项为空数组,只会在组件首次挂载时执行一次。此时App组件的API认证请求大概率还未完成,拿到的是Context的初始isAuth值(false),后续isAuth更新为true后,该useEffect不会重新触发,导致权限校验逻辑无法执行。
  2. 组件挂载时机与异步请求时序不匹配:ProjectTable挂载时,异步认证请求还在处理中,此时读取的isAuth是初始值,后续状态更新无法触发已执行过的校验逻辑。

解决方案一:给useEffect添加isAuth依赖项

修改ProjectTable中的useEffect,将isAuth加入依赖数组,确保每次isAuth状态变化时,重新执行权限校验:

export function ProjectTable({projects}:{projects:Project[]}){
    const { t } = useTranslation();
    const {isAuth} = useUserContext();
    const navigateTo = useNavigate();

    useEffect(() => {
        console.log("isAuth in useEffect ProjectTable",isAuth);

        if (!isAuth){
            navigateTo("/login");
        }
    }, [isAuth, navigateTo]) // 加入isAuth和navigateTo到依赖列表
}

解决方案二:封装权限校验为自定义Hook(更优雅)

把权限校验逻辑抽成可复用的自定义Hook,避免重复代码:

// 自定义权限守卫Hook
export function useAuthGuard() {
    const { isAuth } = useUserContext();
    const navigateTo = useNavigate();

    useEffect(() => {
        if (!isAuth) {
            navigateTo("/login");
        }
    }, [isAuth, navigateTo]);
}

// 在ProjectTable中使用
export function ProjectTable({projects}:{projects:Project[]}){
    const { t } = useTranslation();
    useAuthGuard(); // 直接调用Hook完成权限校验

    // 组件其他业务逻辑...
}

额外优化建议

  1. 处理API请求异常:在App组件的认证请求中添加错误捕获,避免因网络问题或无效token导致isAuth状态异常:
useEffect(() => {
    const token = getToken();
    if (!token) {
        setIsAuth(false);
        return;
    }

    fetch(import.meta.env.VITE_API_URL+"/isAuth", {
        headers: {Authorization: `Bearer ${token}`}
    })
    .then((res) => {
        if (!res.ok) throw new Error('认证请求失败');
        return res.json();
    })
    .then((response) => {
        setIsAuth(response.code === 200);
    })
    .catch(() => {
        setIsAuth(false);
        // 可选:直接跳转到登录页
        // navigateTo("/login");
    })
}, [location.pathname, setIsAuth, getToken])
  1. 将认证逻辑移到Context内部:把API校验逻辑放在UserContextProvider中,让Context初始化时就完成状态同步,减少组件间的状态流转:
export function UserContextProvider ({children}:{children:React.ReactNode}){
    const [isAuth, setIsAuth] = useState(false);

    const setToken = (token:string) => {
        window.localStorage.setItem('token', token);
    }

    const getToken = () => {
        return window.localStorage.getItem('token');
    }

    const logout = () => {
        window.localStorage.removeItem('token');
        setIsAuth(false);
    }

    // Provider内部处理认证校验
    useEffect(() => {
        const token = getToken();
        if (!token) {
            setIsAuth(false);
            return;
        }

        fetch(import.meta.env.VITE_API_URL+"/isAuth", {
            headers: {Authorization: `Bearer ${token}`}
        })
        .then((res) => res.json())
        .then((response) => {
            setIsAuth(response.code === 200);
        })
        .catch(() => {
            setIsAuth(false);
        })
    }, []);

    console.log("isAuth in UserContextProvider",isAuth);

    return <UserContext.Provider value={{setToken, getToken, logout, setIsAuth, isAuth }}>
        {children}
    </UserContext.Provider>
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 14:25:28