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

React中使用SWR时点击按钮触发新fetch请求的问题

实现方案

两种主流实现方式,都符合React Hooks调用规则和SWR设计逻辑:

方案1:变更SWR缓存key触发自动重请求

SWR默认以传入的key(这里是你拼接的url字符串)作为缓存唯一标识,只要key发生变化,就会自动发起全新请求。
你可以在请求参数后追加一个可手动更新的标识位,接口会自动忽略多余参数不影响返回结果,实现步骤:

  1. 修改自定义useFetch Hook,支持接收刷新标识参数,拼入请求url:
import useSWR from "swr";

export function useFetch(category, amount, difficulty, refreshFlag = 0) {
  // 追加refresh参数,值变化时url作为SWR key同步变化
  const url = `https://opentdb.com/api.php?amount=${amount}&category=${category}&difficulty=${difficulty}&type=multiple&refresh=${refreshFlag}`;
  const fetcher = (...args) => fetch(...args).then((res) => res.json());

  const { data, error } = useSWR(url, fetcher, {
    revalidateOnFocus: false,
  });

  return {
    data,
    isLoading: !error && !data,
    isError: error,
  };
}
  1. 在Quiz组件内维护刷新标识state,点击「再玩一次」时更新标识值,即可触发自动重请求:
import { useState, useEffect } from "react";
// 其余导入保持原有逻辑

function Quiz() {
  const { category, color } = useSelector((state) => state.start);
  const { amount, difficulty } = useSelector((state) => state.settings);
  const gameEnded = useSelector((state) => state.end.isEnded);
  const dispatch = useDispatch();
  // 新增刷新标识state
  const [refreshFlag, setRefreshFlag] = useState(0);

  const { data, isLoading, isError } = useFetch(category, amount, difficulty, refreshFlag);

  if (isLoading) return <FlowerSpinner color={color} />;
  if (isError) return <div>An error has occured.</div>;

  // 原渲染阶段直接dispatch会触发重渲染警告,移到useEffect中执行
  useEffect(() => {
    if (data?.results) dispatch(updateQuestions(createQuestions(data.results)));
  }, [data, dispatch]);

  const handlePlayAgain = () => {
    // 更新标识值,SWR检测到key变化自动发起新请求
    setRefreshFlag(prev => prev + 1);
    // 此处可添加重置答题进度、分数的业务逻辑
  };

  return (
    <>
      <Questions />
      {gameEnded ? <PlayAgainBtn onClick={handlePlayAgain} /> : <VerifyButton />}
    </>
  );
}

export default Quiz;

方案2:调用mutate方法强制刷新

之前调用mutate未触发新请求,是因为SWR默认对未过期的缓存不会重新拉取,调用时传入强制重验证配置即可生效,实现步骤:

  1. 修改useFetch Hook,对外暴露SWR返回的mutate方法:
import useSWR from "swr";

export function useFetch(category, amount, difficulty) {
  const url = `https://opentdb.com/api.php?amount=${amount}&category=${category}&difficulty=${difficulty}&type=multiple`;
  const fetcher = (...args) => fetch(...args).then((res) => res.json());

  // 解构取出mutate方法
  const { data, error, mutate } = useSWR(url, fetcher, {
    revalidateOnFocus: false,
  });

  return {
    data,
    isLoading: !error && !data,
    isError: error,
    mutate // 对外暴露供外部调用
  };
}
  1. 在Quiz组件中获取mutate方法,点击按钮时调用强制刷新:
import { useEffect } from "react";
// 其余导入保持原有逻辑

function Quiz() {
  const { category, color } = useSelector((state) => state.start);
  const { amount, difficulty } = useSelector((state) => state.settings);
  const gameEnded = useSelector((state) => state.end.isEnded);
  const dispatch = useDispatch();

  // 取出暴露的mutate方法
  const { data, isLoading, isError, mutate } = useFetch(category, amount, difficulty);

  if (isLoading) return <FlowerSpinner color={color} />;
  if (isError) return <div>An error has occured.</div>;

  useEffect(() => {
    if (data?.results) dispatch(updateQuestions(createQuestions(data.results)));
  }, [data, dispatch]);

  const handlePlayAgain = async () => {
    // 传入revalidate: true配置强制发起新请求
    await mutate(undefined, { revalidate: true });
    // 此处可添加重置答题进度、分数的业务逻辑
  };

  return (
    <>
      <Questions />
      {gameEnded ? <PlayAgainBtn onClick={handlePlayAgain} /> : <VerifyButton />}
    </>
  );
}

export default Quiz;

两种方案都可以实现需求,方案1更符合SWR的响应式设计逻辑,不需要手动调用刷新方法,推荐优先使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 23:51:13