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

React useEffect调用函数报Invalid hook call错误解决

报错原因

这个错误是违反React Hook调用规则导致的:

  • React 明确要求 useContext 在内的所有Hook,只能在React函数组件、自定义Hook的顶层作用域调用,不能在普通工具函数、异步函数、条件分支、嵌套回调里调用。
  • 你写的GetMavenlinkClientId是普通异步工具函数,既不是组件也不是自定义Hook,却在函数内部调用了useContext(AppContext),执行到这行的时候就会抛出Invalid hook call错误,和函数定义在组件内还是组件外没有直接关系,核心是Hook的调用位置不符合规则。
修复步骤

改完后完全满足你页面加载拉取凭证、不硬编码client_id、按钮点击携带正确参数调用API的需求:

1. 重写mavenlinkCredentials.js

把Hook逻辑从工具函数里完全剥离,工具函数只做纯数据请求,状态更新方法通过参数传入,不在工具函数内调用任何Hook:

import { doc, getDoc } from "firebase/firestore";
import { db } from "../../firebase";

const GetMavenlinkClientId = async (setMavenlinkClientId) => {
    const mavenlinkRef = doc(db, 'mavenlink', 'application_id');
    const mavenlinkDocSnap = await getDoc(mavenlinkRef)
    
    if(mavenlinkDocSnap.exists()){
        console.log("mavenlink id: ", mavenlinkDocSnap.data());
        console.log(mavenlinkDocSnap.data()['mavenlinkAccessToken'])
        setMavenlinkClientId(mavenlinkDocSnap.data()['application_id'])
    } else {
        console.log("No doc");
    }
}

export default GetMavenlinkClientId;

2. 调整Dashboard.jsx逻辑

  • 把所有useContext调用合并到组件顶层,不要重复调用同一个Context,符合Hook调用规则
  • 调用工具函数时,把组件顶层拿到的状态更新方法作为参数传入
  • 补充边界判断,避免user未加载时读取uid抛出空指针错误

核心修改部分代码如下:

// 组件顶层统一获取Context值,所有Hook都在顶层调用
const {
    isAuthenticated,
    mavenlinkConnected, setMavenlinkConnected,
    maconomyConnected, setMaconomyConnected,
    bambooConnected, setBambooConnected
} = useContext(AppContext);

// 加可选链,避免user未初始化时读uid报错
const uid = user?.uid
const [mavenlinkClientId, setMavenlinkClientId] = useState("");

useEffect(() => {
    if (loading) return;
    if (!user) return navigate("/");
    fetchUserName();

    if(userTokenCode !== null){
        authorizeMavenlink();
    }

    if(isAuthenticated){
        // 传入状态更新方法给工具函数
        GetMavenlinkClientId(setMavenlinkClientId)
    }
    
}, [user, loading]);

额外优化点:如果你已经在AppContext里维护了mavenlinkClientId的全局状态,就不需要在Dashboard组件里重复定义同名useState,直接从Context取值和拿setter即可,避免多份状态不同步。

效果验证

修改完成后:

  • 页面加载完成、用户鉴权通过后会自动从Firebase拉取存储在数据库里的client_id,不需要硬编码在前端代码中,避免凭证泄露
  • 拉取到的client_id会保存在组件状态/全局Context中,用户点击同步账号按钮触发OAuth跳转时,会自动携带正确的client_id参数,不会出现凭证缺失问题
  • 所有Hook都在组件顶层调用,不会再触发Invalid hook call报错

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 22:48:26