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

如何仅在queryKey变化时通过react-query点击按钮获取数据?

解决方案

要实现「仅在Play按钮点击且输入参数变化时发起请求」的需求,核心思路是手动跟踪上一次请求的参数,在点击时对比当前参数与历史参数,仅当参数变化(或首次点击)时触发请求。以下是具体实现方案:

步骤1:在组件中跟踪历史请求参数

在使用useFetchVoiceSample的组件里,新增状态保存上一次发起请求的参数,用来和当前输入值做对比。

步骤2:控制Play按钮的请求触发逻辑

点击按钮时,先判断当前参数是否和历史参数一致:

  • 首次点击(无历史参数):直接发起请求并记录当前参数
  • 参数有变化:发起请求并更新历史参数
  • 参数无变化:不执行任何请求操作

完整代码示例

组件实现

import { useState } from 'react';
import { useFetchVoiceSample } from './your-hook-file-path';

// 假设你的参数类型定义
type GetVoiceSamplePayload = {
  id: string;
  language: string;
  accent: string;
  expressiveness: number;
};

const VoiceSamplePlayer = () => {
  // 表单输入状态(示例,实际根据你的表单逻辑调整)
  const [id] = useState('voice-001');
  const [language, setLanguage] = useState('zh-CN');
  const [accent, setAccent] = useState('mandarin');
  const [expressiveness, setExpressiveness] = useState(50);

  // 保存上一次发起请求的参数
  const [lastRequestedParams, setLastRequestedParams] = useState<GetVoiceSamplePayload | null>(null);

  // 调用自定义Query Hook
  const { refetch, data, isLoading } = useFetchVoiceSample({
    id,
    language,
    accent,
    expressiveness,
  });

  // 处理Play按钮点击事件
  const handlePlayClick = () => {
    const currentParams = { id, language, accent, expressiveness };

    // 判断是否需要发起请求:首次点击 或 参数发生变化
    const needRefetch = !lastRequestedParams || (
      currentParams.id !== lastRequestedParams.id ||
      currentParams.language !== lastRequestedParams.language ||
      currentParams.accent !== lastRequestedParams.accent ||
      currentParams.expressiveness !== lastRequestedParams.expressiveness
    );

    if (needRefetch) {
      refetch();
      setLastRequestedParams(currentParams);
    }
  };

  return (
    <div className="voice-sample-form">
      {/* 滑块1:Expressiveness */}
      <div>
        <label>表现力:{expressiveness}</label>
        <input
          type="range"
          min="0"
          max="100"
          value={expressiveness}
          onChange={(e) => setExpressiveness(Number(e.target.value))}
        />
      </div>

      {/* 下拉选择:Language */}
      <div>
        <label>语言:</label>
        <select value={language} onChange={(e) => setLanguage(e.target.value)}>
          <option value="zh-CN">中文</option>
          <option value="en-US">英文</option>
        </select>
      </div>

      {/* 下拉选择:Accent */}
      <div>
        <label>口音:</label>
        <select value={accent} onChange={(e) => setAccent(e.target.value)}>
          <option value="mandarin">普通话</option>
          <option value="cantonese">粤语</option>
        </select>
      </div>

      {/* Play按钮 */}
      <button onClick={handlePlayClick} disabled={isLoading}>
        {isLoading ? '加载中...' : 'Play'}
      </button>

      {/* 渲染返回的音频数据 */}
      {data && <audio src={data.audioUrl} controls autoPlay />}
    </div>
  );
};

export default VoiceSamplePlayer;

原Hook无需修改

你提供的useFetchVoiceSample Hook保持不变即可,它负责定义查询的queryKey和请求逻辑,由组件控制何时触发refetch。

关键说明

  • 采用逐个字段对比的方式判断参数变化,比JSON.stringify更高效,也避免了对象属性顺序等无关因素导致的误判。
  • lastRequestedParams仅记录实际发起请求的参数,确保后续对比的准确性。
  • 结合isLoading状态禁用按钮,避免重复点击导致的并发请求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 03:51:16