React.js:无法将Promise结果设置为对象数组内的属性
问题描述
API返回的结果里,films、vehicles等属性是URL数组。我想请求这些URL拿到对应的对象数组,再把结果更新回原属性里。用Promise.all处理后,赋值给films和vehicles时,得到的却是Promise状态(有时是pending,有时显示完成但不是对象数组),想要的是让newState里的对象的films和vehicles变成对象数组。
以下是我的代码:
import { useEffect, useState } from "react"; const url = `https://swapi.dev/api/people/`; export function ToDo() { const [results, setResults] = useState([]); useEffect(() => { apiCallHandler(url); }, []); async function asyncAllPromises(arr) { const promises = await arr.map(async (item) => { const response = await fetch(item, { cache: "no-cache" }); const json = await response.json(); return json; }); const response = await Promise.all(promises); return response; } const apiCallHandler = async () => { try { const response = await fetch(url); let data = await response.json(); let newState = data.results.map((result) => { result.films = asyncAllPromises(result.films).then((data) => data); result.vehicles = asyncAllPromises(result.vehicles).then( (data) => data ); return result; }); setResults(newState); } catch (error) { console.error("Unable to find data", error); } }; console.log("results", results); const table = results && results.length ? ( <table> <thead> <tr> <td>Name</td> <td>Mass</td> </tr> </thead> <tbody> {results.map((result, index) => { return ( <tr key={index}> <td>{result.name}</td> <td>{result.mass}</td> </tr> ); })} </tbody> </table> ) : ( "Loading.." ); return <> {table} </>; }
解决方案
1. 先修正asyncAllPromises函数的错误
你在arr.map前加了await,但map是同步方法,返回的是Promise数组而非单个Promise,这行await完全多余,会直接返回原数组。修正后:
async function asyncAllPromises(arr) { const promises = arr.map(async (item) => { const response = await fetch(item, { cache: "no-cache" }); return response.json(); }); return Promise.all(promises); }
2. 等待所有异步请求完成后再更新状态
原来的map遍历是同步的,内部的异步操作不会等待完成,直接把Promise赋值给了films和vehicles。要改成异步遍历,用Promise.all等待所有结果处理完毕再更新状态:
const apiCallHandler = async () => { try { const response = await fetch(url); const data = await response.json(); // 对每个结果做异步处理,替换films/vehicles为对象数组 const newState = await Promise.all(data.results.map(async (result) => { // 复制原对象,避免直接修改原数据(可选但推荐) const updatedResult = { ...result }; updatedResult.films = await asyncAllPromises(result.films); updatedResult.vehicles = await asyncAllPromises(result.vehicles); return updatedResult; })); setResults(newState); } catch (error) { console.error("Unable to find data", error); } };
3. 问题根源解释
- 直接给
result.films赋值asyncAllPromises(...),本质是把Promise对象存进了属性,而不是等待Promise resolve后的最终数组 map是同步遍历,不会等待内部的异步操作完成,所以newState里的属性全是未完成或刚完成的Promise,不是你要的对象数组
额外优化:完善加载状态
可以加个专门的加载状态,避免初始空数组阶段的异常显示:
const [results, setResults] = useState([]); const [loading, setLoading] = useState(true); // 在apiCallHandler里,请求完成后关闭加载状态 const apiCallHandler = async () => { try { // ... 原有处理代码 setResults(newState); } catch (error) { console.error("Unable to find data", error); } finally { setLoading(false); } }; // 渲染部分调整 const table = loading ? ( "Loading.." ) : ( <table> {/* 原有表格内容 */} </table> );
内容的提问来源于stack exchange,提问作者Subhojit
相关产品推荐
相关产品推荐

