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

React Hook useQuery回调调用报错,附Next.js代码寻求解决方案

解决React Hook规则错误:在回调中调用useQuery

错误原因

React Hook的核心规则要求所有Hook必须在函数组件的顶层作用域调用,不能在循环、条件判断、嵌套函数(比如map回调)中执行。你在points.map()里调用useQuery,会导致Hook的调用顺序在每次渲染时可能变化,破坏React对Hook状态的跟踪机制,因此触发react-hooks/rules-of-hooks规则报错。

两种可行解决方案

方案1:使用Apollo Client的useQueries钩子(快速适配)

Apollo Client提供了useQueries钩子,专门用于批量执行多个查询,完美符合Hook规则。它接收一个查询配置数组,返回对应结果的数组,和你之前的逻辑兼容。

修改后的代码:

'use client';

import React from 'react';
// @ts-ignore
import CanvasJSReact from '@canvasjs/react-charts';
import { useQueries } from '@apollo/client'; // 替换useQuery为useQueries
import { OVERALL_PERCENTAGE_SECONDARY } from '@/app/graphql/queries/student-score/overallPercentageSecondaryQueries';

const CanvasJSChart = CanvasJSReact.CanvasJSChart;

const ScoreChart = ({ school, stfn }: { school: string; stfn: string }) => { // 替换any为明确类型
  const points = [5, 4, 3, 2, 1];

  // 用useQueries批量执行查询,顶层调用符合Hook规则
  const queries = useQueries(
    points.map(point => ({
      query: OVERALL_PERCENTAGE_SECONDARY,
      variables: { school, stfn, points: point },
    }))
  );

  const loading = queries.some(query => query.loading);
  const error = queries.find(query => query.error)?.error;

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  const overallPercentages = queries.map(query => query.data?.overallPercentageByPoints || { numof_question: 0, question: [] });

  const optionsChart = {
    animationEnabled: true,
    exportEnabled: false,
    theme: "light1",
    data: [{
      type: "pie",
      indexLabel: "{label}: {y}%",
      startAngle: -90,
      dataPoints: overallPercentages.map((percentage, index) => ({ y: percentage.overall, label: ["SA", "A", "N", "D", "SD"][index] })),
    }]
  };

  return (
    <div>
      <p className='text-sm text-center font-bold'>Score Chart</p>
      <CanvasJSChart options={optionsChart} containerProps={{ width: '100%', height: '170px' }} />
    </div>
  );
};

export default ScoreChart;

方案2:修改GraphQL查询为批量查询(性能更优)

如果后端支持,建议修改GraphQL查询,一次性获取所有points对应的数据,减少网络请求次数,提升性能。

  1. 新增批量查询定义:
# overallPercentageSecondaryQueries.ts
export const OVERALL_PERCENTAGE_SECONDARY_BATCH = gql`
  query OverallPercentageSecondaryBatch($school: String!, $stfn: String!, $points: [Int!]!) {
    overallPercentageByPointsBatch(school: $school, stfn: $stfn, points: $points) {
      points
      overall
      numof_question
      question
    }
  }
`;
  1. 组件中使用单个useQuery:
'use client';

import React from 'react';
// @ts-ignore
import CanvasJSReact from '@canvasjs/react-charts';
import { useQuery } from '@apollo/client';
import { OVERALL_PERCENTAGE_SECONDARY_BATCH } from '@/app/graphql/queries/student-score/overallPercentageSecondaryQueries';

const CanvasJSChart = CanvasJSReact.CanvasJSChart;

const ScoreChart = ({ school, stfn }: { school: string; stfn: string }) => {
  const points = [5, 4, 3, 2, 1];

  const { loading, error, data } = useQuery(OVERALL_PERCENTAGE_SECONDARY_BATCH, {
    variables: { school, stfn, points },
  });

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  // 按points的原始顺序整理数据
  const resultMap = new Map(data?.overallPercentageByPointsBatch.map(item => [item.points, item]));
  const overallPercentages = points.map(point => resultMap.get(point) || { numof_question: 0, question: [], overall: 0 });

  const optionsChart = {
    animationEnabled: true,
    exportEnabled: false,
    theme: "light1",
    data: [{
      type: "pie",
      indexLabel: "{label}: {y}%",
      startAngle: -90,
      dataPoints: overallPercentages.map((percentage, index) => ({ y: percentage.overall, label: ["SA", "A", "N", "D", "SD"][index] })),
    }]
  };

  return (
    <div>
      <p className='text-sm text-center font-bold'>Score Chart</p>
      <CanvasJSChart options={optionsChart} containerProps={{ width: '100%', height: '170px' }} />
    </div>
  );
};

export default ScoreChart;

方案对比

  • 方案1:无需修改后端,直接适配现有查询,适合快速修复问题。
  • 方案2:减少网络请求次数,性能更优,是长期优化的首选方案,需要后端配合实现批量查询接口。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 00:27:26