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

如何基于自定义useFetch Hook实现数据刷新功能?

为自定义useFetch Hook添加数据刷新功能

我自己写了一个简易的useFetch Hook用来从API获取数据,但验收要求必须支持数据刷新功能。请问在当前的代码结构下,怎么实现重新调用接口获取数据?

现有代码

useFetch.tsx

const useFetch = (url: string) => {
  console.log('useFetch', url);
  const [isLoading, setIsLoading] = useState(false);
  const [data, setData] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      setIsLoading(true);
      await fetch(url)
        .then((res) => res.json())
        .then((data) => {
          const doSet = () => {
            setData(data);
            setIsLoading(false);
          };
          // TODO: Remove timout, just for exhibiting longer loading
          // doSet();
          setTimeout(() => doSet(), 1000);
        });
    };
    fetchData();
  }, [url]);

  return { data, isLoading };
};

export default useFetch;

App.tsx

const {data, isLoading} = useFetch('some-api.com');

return (
    <div>
        <button onClick={refresh}>Refresh</button>

       {
           isLoading 
              ? <span>Loading data...</span>
              : data.map(d => <div>{d}</div>)
       }
    </div>
)

解决方案

方法一:在Hook中暴露刷新函数(推荐)

这种方法最直观,把请求逻辑抽成独立函数,同时返回一个refresh方法给外部组件调用:

1. 修改useFetch.tsx

const useFetch = (url: string) => {
  console.log('useFetch', url);
  const [isLoading, setIsLoading] = useState(false);
  const [data, setData] = useState(null);

  // 把请求逻辑抽成独立函数
  const fetchData = async () => {
    setIsLoading(true);
    await fetch(url)
      .then((res) => res.json())
      .then((data) => {
        const doSet = () => {
          setData(data);
          setIsLoading(false);
        };
        // TODO: Remove timout, just for exhibiting longer loading
        // doSet();
        setTimeout(() => doSet(), 1000);
      });
  };

  // 初始挂载时自动请求
  useEffect(() => {
    fetchData();
  }, [url]);

  // 暴露refresh方法,供外部主动触发刷新
  return { data, isLoading, refresh: fetchData };
};

export default useFetch;

2. 修改App.tsx

从Hook的返回值中解构出refresh,绑定到按钮点击事件:

const { data, isLoading, refresh } = useFetch('some-api.com');

return (
    <div>
        <button onClick={refresh}>Refresh</button>

       {
           isLoading 
              ? <span>Loading data...</span>
              : data?.map(d => <div key={d.id}>{d}</div>) {/* 加可选链避免null报错,添加key符合React规范 */}
       }
    </div>
)

方法二:通过修改URL依赖触发刷新(不推荐)

如果不想改动Hook,可以给URL加一个可变参数(比如递增的key),强制触发useEffect的依赖更新,从而重新请求:

import { useState } from 'react';
import useFetch from './useFetch';

const App = () => {
  const [refreshKey, setRefreshKey] = useState(0);
  // 给URL添加可变参数
  const url = `some-api.com?refresh=${refreshKey}`;
  const { data, isLoading } = useFetch(url);

  const refresh = () => {
    // 更新key,触发URL变化
    setRefreshKey(prev => prev + 1);
  };

  return (
    <div>
      <button onClick={refresh}>Refresh</button>
      {
        isLoading 
          ? <span>Loading data...</span>
          : data?.map(d => <div key={d.id}>{d}</div>)
      }
    </div>
  );
};

export default App;

这种方法的缺点是会修改请求URL,可能不符合API的要求,而且不够直观,所以优先选方法一。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 19:32:42