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

修复React useReactiveVar条件调用触发的Hooks规则ESLint报错

问题报错

React组件渲染时触发ESLint Hooks规则报错:

React Hook "useReactiveVar" is called conditionally. React Hooks must be called in the exact same order in every component render(eslintreact-hooks/rules-of-hooks)

报错原因

该报错触发的核心原因是违反了React Hooks的基础调用规则:所有Hook必须在自定义Hook/组件的顶层作用域调用,不能放在条件判断、循环、嵌套函数中,否则每次渲染时Hook的调用顺序不一致,会直接导致React状态匹配错乱。
原代码中将useReactiveVar放在了isClient()的三元判断分支中,属于典型的条件调用Hook场景,因此被ESLint规则拦截。

修复方案

核心调整思路是把所有Hook调用提到顶层,将「条件调用Hook」改为「Hook无条件调用、返回值按需使用」,同时做好非客户端环境的兜底逻辑,不影响原有SSR/客户端双端的业务表现。
修复后的完整代码如下:

import { useEffect, useMemo } from 'react';
import { useApolloClient, useReactiveVar, makeVar } from '@apollo/client';
import isClient from 'commons/isClient';

import useVisitorLocationHook from '../useVisitorLocationHook';
import ClosestOrderSampleValue from './ClosestOrderSampleValue';
import storesData from './stores.json';

// 服务端渲染场景兜底用的空响应式变量,不会触发状态更新
const dummyReactiveVar = makeVar({});

const useClosestStoreOrderSample = () => {
  const client = useApolloClient();
  // 顶层统一获取响应式变量实例,非客户端环境用兜底实例
  const closestOrderSampleValueVar = useMemo(() => {
    if (!isClient()) return dummyReactiveVar;
    return client.cache.jbReactiveVars.closestOrderSampleValueVar;
  }, [client]);
  // 顶层无条件调用useReactiveVar,彻底符合Hooks规则
  const reactiveVarValue = useReactiveVar(closestOrderSampleValueVar);
  // 非客户端环境直接使用默认兜底值,不读取Hook返回结果
  const { loading = false, OrderSampleValue = null, forUserZip = null } = isClient()
    ? reactiveVarValue
    : {};
  const [userLocation] = useVisitorLocationHook();

  useEffect(() => {
    // 非客户端环境直接跳过数据拉取逻辑
    if (!isClient()) return;
    if (!userLocation?.zip || userLocation.zip === forUserZip) return;
    ClosestOrderSampleValue.fetchClosestOrderSampleValuecode(client, userLocation.zip);
  // 补全依赖数组缺失项,避免闭包引用旧值问题
  }, [userLocation, client, forUserZip]);

  return {
    storeLocation: isClient() && OrderSampleValue ? storesData[OrderSampleValue] : null,
    isOrderSampleValueLoading: !userLocation?.zip ? false : loading,
  };
};

export default useClosestStoreOrderSample;

关键调整点

  • 移除useReactiveVar外层的条件判断,保证每次渲染Hook调用顺序完全一致,直接解决ESLint报错
  • 新增服务端兜底用的空响应式变量,避免非客户端环境下传空值给useReactiveVar引发运行时错误
  • 保留原有的双端判断逻辑:非客户端环境下不读取Hook返回值,直接使用默认兜底值,不影响原有SSR渲染逻辑
  • 补全useEffect依赖数组中缺失的client、forUserZip项,避免闭包陷阱导致的逻辑异常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 14:57:22