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

Next.js关闭Strict Mode后API仍多次触发的问题及解决方法

解决Next.js中React Query API重复调用四次的问题

问题分析

当selectedAmc值变更时,API被触发四次,即使关闭Next.js严格模式也无法解决。当前代码通过useEffect手动调用React Query的refetch方法触发请求,核心问题可能出在:

  • refetch函数引用不稳定,导致useEffect因依赖变化重复执行
  • 组件不必要的重复渲染
  • 未利用React Query内置的请求自动管理机制,手动触发逻辑存在冗余

解决方案

方案1:改用React Query自动触发请求(推荐)

利用React Query的查询键和enabled配置,让框架自动管理请求触发,避免手动副作用的问题:

import { Select } from "antd";
import React from "react";
import { useQuery } from "react-query";
import { postSchemeName } from "../../../pages/mis-reports/mis-api";

const { Option } = Select;

type Props = {
  className?: string;
  selectedAmc?: string;
};

const SchemeName = ({ className, selectedAmc }: Props) => {
  // 自动触发查询,无需手动refetch和useEffect
  const { data: schemeData } = useQuery<any, any>(
    // 查询键:selectedAmc变化时自动视为新查询
    ["post-scheme", selectedAmc],
    // 明确传递API所需参数
    () => postSchemeName({ fund_house_name: selectedAmc }),
    {
      // 仅当selectedAmc存在时执行查询
      enabled: !!selectedAmc,
      // 关闭非必要的自动重请求,避免额外调用
      refetchOnWindowFocus: false,
      refetchOnReconnect: false,
      // 设置缓存时间,相同参数自动复用缓存
      cacheTime: 5 * 60 * 1000, // 5分钟
    }
  );

  const onChange = (value: string) => {};
  const onSearch = (value: string) => {};

  console.log("selected amc--->", selectedAmc);

  return (
    <>
      <div className="mb-4 xxs:w-[100%] xs:w-[45%] sm:w-[30%]">
        <p className="mb-1">Scheme Name</p>
        <Select
          className={`h-10 ${className} w-full`}
          showSearch
          size="large"
          placeholder="Scheme Name..."
          optionFilterProp="children"
          onChange={onChange}
          onSearch={onSearch}
          filterOption={(input, option) =>
            (option!.children as unknown as string)
              .toLowerCase()
              .includes(input.toLowerCase())
          }
        >
          {/* 用接口返回数据渲染选项 */}
          {schemeData?.map(scheme => (
            <Option key={scheme.value} value={scheme.value}>
              {scheme.label}
            </Option>
          )) || <Option value="hellp">hello</Option>}
        </Select>
      </div>
    </>
  );
};

// 用React.memo避免不必要的重渲染
export default React.memo(SchemeName);

方案2:手动触发时限制重复调用(兼容原有逻辑)

如果必须保留手动触发逻辑,可通过useRef标记请求状态,避免重复执行:

import { Select } from "antd";
import React, { useEffect, useRef } from "react";
import { useQuery } from "react-query";
import { postSchemeName } from "../../../pages/mis-reports/mis-api";

const { Option } = Select;

type Props = {
  className?: string;
  selectedAmc?: string;
};

const SchemeName = ({ className, selectedAmc }: Props) => {
  const { data: schemeData, refetch: fetchSchemeName } = useQuery<any, any>(
    ["post-scheme", { fund_house_name: selectedAmc }],
    postSchemeName,
    {
      enabled: false,
    }
  );

  // 标记当前selectedAmc是否已触发过请求
  const isFetched = useRef(false);

  useEffect(() => {
    if (!selectedAmc) return;

    // 同一selectedAmc值只触发一次请求
    if (isFetched.current) return;

    fetchSchemeName()
      .then(() => {
        isFetched.current = true;
      })
      .catch(() => {
        // 请求失败时重置标记,允许重试
        isFetched.current = false;
      });

    // selectedAmc变化时重置标记
    return () => {
      isFetched.current = false;
    };
  }, [selectedAmc, fetchSchemeName]);

  const onChange = (value: string) => {};
  const onSearch = (value: string) => {};

  console.log("selected amc--->", selectedAmc);

  return (
    <>
      <div className="mb-4 xxs:w-[100%] xs:w-[45%] sm:w-[30%]">
        <p className="mb-1">Scheme Name</p>
        <Select
          className={`h-10 ${className} w-full`}
          showSearch
          size="large"
          placeholder="Scheme Name..."
          optionFilterProp="children"
          onChange={onChange}
          onSearch={onSearch}
          filterOption={(input, option) =>
            (option!.children as unknown as string)
              .toLowerCase()
              .includes(input.toLowerCase())
          }
        >
          <Option value="hellp">hello</Option>
        </Select>
      </div>
    </>
  );
};

export default React.memo(SchemeName);

额外排查点

  1. 检查父组件中selectedAmc是否被多次更新,导致组件重复触发请求
  2. 确认postSchemeName接口内部是否存在重复调用逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 03:50:32