React嵌套数组数据获取:星战主题REST API应用开发问询
嘿,刚好我之前折腾过SWAPI的React小项目,这个嵌套URL的问题其实用Promise.all加React的状态管理就能轻松搞定,我给你一步步拆解:
1. 先搞定基础人物列表的获取
首先用React的useEffect和useState获取people接口的初始数据,先把基础人物信息存起来:
import { useState, useEffect } from 'react'; const StarWarsApp = () => { const [people, setPeople] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { const fetchPeople = async () => { try { const res = await fetch('https://swapi.dev/api/people/'); const data = await res.json(); // 先存基础人物数据,后面再补关联的嵌套数据 setPeople(data.results); setLoading(false); } catch (err) { console.error('获取人物数据翻车了:', err); setLoading(false); } }; fetchPeople(); }, []); if (loading) return <div>加载中... 正在召唤绝地武士 🛐</div>;
2. 写个通用工具函数批量拉取嵌套URL数据
因为像films、species这些字段都是URL数组,咱们写个复用函数来批量请求这些数据,省得重复写代码:
// 传入URL数组,返回对应的数据数组 const fetchNestedData = async (urls) => { try { // 把每个URL转成fetch请求,然后用Promise.all并行执行 const requests = urls.map(url => fetch(url).then(res => res.json())); return await Promise.all(requests); } catch (err) { console.error('嵌套数据获取失败:', err); return []; } };
3. 拆分出子组件处理单个人物的详情
把单个人物的渲染拆成子组件,这样可以单独处理每个人物的嵌套数据,父组件逻辑会更清爽:
const PersonCard = ({ person }) => { const [films, setFilms] = useState([]); const [species, setSpecies] = useState([]); const [cardLoading, setCardLoading] = useState(true); useEffect(() => { const fetchPersonDetails = async () => { // 并行获取电影和物种数据,提升加载速度 const [filmsData, speciesData] = await Promise.all([ fetchNestedData(person.films), fetchNestedData(person.species) ]); setFilms(filmsData); setSpecies(speciesData); setCardLoading(false); }; fetchPersonDetails(); }, [person]); if (cardLoading) return <div className="card-loading">加载人物详情...</div>; return ( <div className="person-card"> <h2>{person.name}</h2> <p>身高: {person.height}cm</p> <p>体重: {person.mass}kg</p> <h3>参演电影:</h3> <ul> {films.map(film => ( <li key={film.episode_id}>{film.title}</li> ))} </ul> <h3>所属物种:</h3> <ul> {species.map(specie => ( <li key={specie.name}>{specie.name}</li> ))} </ul> </div> ); };
4. 父组件里映射人物列表
最后回到父组件,把每个人物数据传给子组件渲染就行:
return ( <div className="app-container"> <h1>星战人物列表 🚀</h1> <div className="people-grid"> {people.map(person => ( <PersonCard key={person.url} person={person} /> ))} </div> </div> ); }; export default StarWarsApp;
额外小贴士
- 可以加个缓存机制(比如用
useMemo或者本地存储),避免重复请求相同的URL(比如很多人物都参演同一部电影,不用每次都拉一遍) - 如果数据量很大,记得用上SWAPI的分页参数(
?page=2)做分页加载,不然一次性拉太多会慢 - 错误处理可以再完善点,比如给用户显示友好的错误提示,而不是只在控制台打印
内容的提问来源于stack exchange,提问作者Brandon Benefield
相关产品推荐
相关产品推荐

