如何在React/Gatsby中实现多请求并处理返回结果
问题描述
我正在尝试在Gatsby应用中实现多数据库请求并展示结果,目前已实现单请求的可行方案,代码如下:
const ListRezept = (props) => { const url_id = props.params.id; const [data, setData] = useState(null); const [isPending, setIsPending] = useState(true); const [error, setError] = useState(null); useEffect(() => { const abortCont = new AbortController(); setTimeout(() => { fetch('https://abc.4.azurestaticapps.net/data-api/rest/Rezept?$filter=RezeptId eq '+ url_id) .then(res => { if (!res.ok) { // error coming back from server console.log("error"); throw Error('Could not fetch the data for that resource!'); } return res.json(); }) .then(data => { setIsPending(false); setData(data.value); setError(null); }) .catch(err => { if (err.name === 'AbortError') { console.log('fetch aborted') } else { // auto catches network / connection error setIsPending(false); setError(err.message); } }); }, []); // abort the fetch return () => abortCont.abort(); }, []) ... }
现在我想集成Promise.all函数来发起多请求,但不知道如何处理Promise.all的多个返回结果,尝试的失败代码如下:
const rezeptreq = fetch('https://abc.4.azurestaticapps.net/data-api/rest/Rezept?$filter=RezeptId eq '+ url_id); const rezeptartreq = fetch('https://abc.4.azurestaticapps.net/data-api/rest/Rezeptart'); Promise.all([rezeptreq, rezeptartreq]) .then(([res1, res2 ]) => { if (!res1.ok) { // error coming back from server console.log("error"); throw Error('Could not fetch the data for that resource!'); } return res.json(), res2.json(); ...
我的需求是将每个请求的结果映射到变量中,请问是否需要创建数组?该如何访问每个请求的单独结果?
解决方案
核心逻辑
Promise.all会等待所有传入的Promise完成后,返回一个包含所有结果的数组。你需要先逐个处理每个fetch的响应状态,解析JSON,再将结果分别存入对应的状态变量即可,无需额外创建数组存储。
完整可运行代码
const ListRezept = (props) => { const url_id = props.params.id; // 为每个请求的结果声明独立状态 const [rezeptData, setRezeptData] = useState(null); const [rezeptartData, setRezeptartData] = useState(null); const [isPending, setIsPending] = useState(true); const [error, setError] = useState(null); useEffect(() => { const abortCont = new AbortController(); const signal = abortCont.signal; // 封装单个请求逻辑:包含状态检查和JSON解析 const getRezept = () => { return fetch(`https://abc.4.azurestaticapps.net/data-api/rest/Rezept?$filter=RezeptId eq ${url_id}`, { signal }) .then(res => { if (!res.ok) throw Error('获取Rezept数据失败'); return res.json(); }); }; const getRezeptart = () => { return fetch('https://abc.4.azurestaticapps.net/data-api/rest/Rezeptart', { signal }) .then(res => { if (!res.ok) throw Error('获取Rezeptart数据失败'); return res.json(); }); }; // 并行发起多个请求 Promise.all([getRezept(), getRezeptart()]) .then(([rezeptResult, rezeptartResult]) => { // 解构结果,分别存入对应状态 setRezeptData(rezeptResult.value); setRezeptartData(rezeptartResult.value); setIsPending(false); setError(null); }) .catch(err => { if (err.name === 'AbortError') { console.log('请求已取消'); } else { setIsPending(false); setError(err.message); } }); // 组件卸载时取消所有请求 return () => abortCont.abort(); }, [url_id]); // 依赖url_id,参数变化时自动重新请求 // 渲染逻辑 if (error) return <div>错误提示:{error}</div>; if (isPending) return <div>加载中...</div>; return ( <div className="rezept-container"> <h3>Rezept详情</h3> {rezeptData && <div>{JSON.stringify(rezeptData)}</div>} <h3>Rezeptart列表</h3> {rezeptartData && <div>{JSON.stringify(rezeptartData)}</div>} </div> ); };
关键细节说明
- 独立状态管理:为每个请求的结果创建单独的
useState变量,后续可以直接通过rezeptData和rezeptartData访问各自的结果,无需额外数组。 - 请求封装:把每个请求的逻辑封装成函数,统一处理响应状态校验和JSON解析,避免重复代码,也方便后续维护。
- AbortController全局控制:将
signal传入所有fetch请求,确保组件卸载时所有未完成的请求都能被取消,避免内存泄漏。 - 结果解构:在
Promise.all的then回调中,使用数组解构语法[rezeptResult, rezeptartResult]直接获取每个请求的解析后结果,对应顺序就是传入Promise.all的请求顺序。 - 错误统一处理:任何一个请求失败都会触发
catch块,你可以根据错误信息区分不同请求的失败原因,也可以统一展示错误提示。
你之前代码的问题修正
- 错误使用逗号运算符:
return res.json(), res2.json()只会返回最后一个JSON解析结果,正确做法是用Promise.all([res1.json(), res2.json()])并行解析两个响应。 - 遗漏第二个请求的状态检查:需要对
res2也做res2.ok的判断,否则第二个请求失败时不会抛出错误。
内容的提问来源于stack exchange,提问作者user23348508
相关产品推荐
相关产品推荐

