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

React/Next.js中useSWR首次点击搜索API返回undefined问题

根本原因

这个问题和React的渲染机制、useSWR的异步请求逻辑直接相关,有两个核心诱因:

  • React组件每次渲染产生的状态都是快照,你在点击事件回调中拿到的data,是点击发生时当前已经完成的渲染周期里的旧值,不会同步等待接口请求返回后再更新。
  • useSWR发起请求是异步行为:你点击按钮执行setShouldFetch(true)后,首先要等React批量更新状态触发组件重渲染,useSWR才会识别到新的key、发起接口请求,等请求成功后会再次触发组件重渲染,data才会被赋值为接口返回值。你在点击回调里直接同步打印data时,上述流程还没走完,第一次点击时data还是初始的undefined,第二次点击时打印的是第一次请求完成后更新的data值,所以看起来是第二次点击才拿到结果。

问题复现截图:
问题复现控制台输出截图

解决方案

方案1:监听data变化处理返回结果

不要在点击回调里直接打印/处理data,通过useEffect监听data的变化,等请求完成data更新后再执行后续逻辑:

// 在组件内添加以下逻辑
useEffect(() => {
  // 可在这里处理请求返回结果,比如打印、渲染、存到其他状态等
  if (data) {
    console.log('接口返回数据:', data);
  }
}, [data]);

点击回调里只保留触发请求的逻辑即可:

<button
  onClick={() => {
    setShouldFetch(true);
    console.log('当前搜索词:', searchTerm);
  }}
>
  Search!
</button>

方案2:优化请求触发逻辑(更符合SWR的使用习惯)

可以去掉shouldFetch状态,用专门的查询参数状态控制是否发起请求,避免多次点击的状态冲突:

export default function Home() {
  const [searchTerm, setSearchTerm] = useState('');
  // 仅在点击搜索时更新该状态,触发SWR发起请求
  const [activeQuery, setActiveQuery] = useState(null);
  const fetcher = (url) => fetch(url).then((res) => res.json());

  const { data, error } = useSWR(
    activeQuery 
      ? `https://eu-central-1.aws.webhooks.mongodb-realm.com/api/client/v2.0/app/lottigully-jjrda/service/movies/incoming_webhook/movies?arg=${activeQuery}`
      : null,
    fetcher
  );

  // 监听data变化处理结果
  useEffect(() => {
    if (data) console.log('搜索结果:', data);
  }, [data]);

  if (error) return 'An error has occurred.';

  return (
    <>
      <main>
        <div className={style.main_container}>
          <NavBar />
          <Hero />
        </div>
        <div className={style.search_container}>
          <SearchBar
            onChange={(e) => setSearchTerm(e.target.value)}
          />
          <button
            onClick={() => {
              setActiveQuery(searchTerm);
              console.log('当前搜索词:', searchTerm);
            }}
          >
            Search!
          </button>
          {/* 渲染时必须判断data存在再访问内部属性 */}
          {data && <div>搜索结果展示:{JSON.stringify(data)}</div>}
        </div>
      </main>
    </>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 12:36:04