如何基于自定义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
相关产品推荐
相关产品推荐

