同时处理两个API
Posted
技术标签:
【中文标题】同时处理两个API【英文标题】:Handle two APIs at the same time 【发布时间】:2021-01-10 08:25:28 【问题描述】:我想使用 React 从 API 加载行星数据并将这些数据放入 Material UI 卡组件中。不幸的是,我使用的行星 API 没有照片,我也想在卡片中显示。为此,我正在使用另一个 API。
获取行星数据的API:https://api.le-systeme-solaire.net/rest 获取行星图片的API:https://images-api.nasa.gov/search
我已经弄清楚如何将每个行星组件及其各自的信息渲染到卡片中,但不知道如何将每个 NASA 图像映射到各自的行星:
这是 App.js 组件的代码:
import React, useState, useEffect from 'react';
import './App.css';
import axios from 'axios'
import Block from "./Block"
function App()
const [planets, setPlanets] = useState([])
const [images, setImages] =useState([])
const getPlanets = async()=>
const data = await fetch
('https://api.le-systeme-solaire.net/rest/bodies') //Await for first fetch promise to resolve
const planets = await(data.json()) //Await for data.json to resolve and save this planets
setPlanets(planets.bodies.filter
(planet =>planet.isPlanet && planet.name.indexOf('1')===-1))
const getImages = (name)=>
axios.get('https://images-api.nasa.gov/search',
params:
q: name
)
.then(res =>
setImages(images.concat(res.data.collection.items[0].links[0].href)))
console.log(planets)
useEffect(()=>
getPlanets();
,[])
useEffect(()=>
if(planets)
planets.map(planet =>getImages(planet.englishName))
,[])
console.log(images)
console.log(planets.length)
return (
<div className="App">
planets.map(planet =>
(<Block
key = planet.id
id = planet.id
name = planet.englishName
dateDiscovered = planet.discoveryDate
mass = planet.mass.massValue
massExp = planet.mass.massExponent
image = ???
/>)
)
</div>
);
export default App;
Block.js的代码如下:
import React, useState, useEffect from 'react'
import './Block.css'
import Card, CardContent from '@material-ui/core'
function Block(props)
return (
<div>
<Card>
<CardContent>
<div className = "planetInfo">
<h4>props.name</h4>
<h5>Mass: props.mass*10^props.massExp kg</h5>
<h5>Discovery Date: props.dateDiscovered</h5>
<h5>ID: props.id</h5>
<img src = props.image/>
</div>
</CardContent>
</Card>
</div>
)
export default Block
我感觉我的结构不正确。任何帮助将不胜感激。
【问题讨论】:
您能否提供一个用于行星和图像的 JSON 示例。 (来自您的 console.logs) 【参考方案1】:您可以根据数组索引轻松绘制行星和图像 - 假设:
你按顺序检索它们
因为有 8 个行星,所以会有 8 个图像;所以你的Array.map
函数看起来像:
planets.map((planet,index) =>
(<Block
key = planet.id
id = planet.id
name = planet.englishName
dateDiscovered = planet.discoveryDate
mass = planet.mass.massValue
massExp = planet.mass.massExponent
image = images[index]
/>))
【讨论】:
【参考方案2】:您可以useEffect
,当行星阵列发生变化时,您可以遍历行星阵列中行星的名称并调用图像 API。
React.useEffect(() =>
async function fetchAllImages()
const allImages = [];
for await (const planet of planets)
const data = axios.get('https://images-api.nasa.gov/search',
params:
q: planet.name
)
allImages.push(data);
setImages(allImages);
fetchAllImages();
, [planets])
【讨论】:
【参考方案3】:同时处理多个 API 调用是一个非常困难的问题。我不完全知道这是否可行,但你为什么不改变
const [images, setImages] =useState([])
到 const [images, setImages] =useState()
和
axios.get('https://images-api.nasa.gov/search',
params:
q: name
)
.then(res => setImages(images.concat(res.data.collection.items[0].links[0].href)))
到
axios.get('https://images-api.nasa.gov/search',
params:
q: name
)
.then(res =>
images[name] = res.data.collection.items[0].links[0].href));
setImages(...images);
)
然后您可以循环使用 planets
数组根据植物名称从 images
对象中选择 URL。
【讨论】:
【参考方案4】:我建议将两个数据获取组合成一个效果挂钩回调。首先获取并过滤真实行星的天体列表,然后获取图像并将行星和图像映射到单个行星数据数组中。现在只需将image=planet.image
传递给Block
。
function App()
const [planets, setPlanets] = useState([]);
const getPlanets = async () =>
const data = await fetch("https://api.le-systeme-solaire.net/rest/bodies"); //Await for first fetch promise to resolve
const planets = await data.json(); //Await for data.json to resolve and save this planets
// filter planet data
const filteredPlanets = planets.bodies.filter(
(planet) => planet.isPlanet && planet.name.indexOf("1") === -1
);
// define function here to avoid needing it as dependency
// return GET request response image value
const getImages = (name) =>
return axios
.get("https://images-api.nasa.gov/search",
params:
q: name
)
.then((res) => res.data.collection.items[0].links[0].href);
;
// Fetch and await all images
const planetImages = await Promise.all(
filteredPlanets.map((planet) => getImages(planet.englishName))
);
// Merge planets and images arrays
const planetsWithImages = filteredPlanets.map((planet, i) => (
...planet,
image: planetImages[i]
));
setPlanets(planetsWithImages);
;
useEffect(() =>
getPlanets();
, []);
return (
<div className="App">
planets.map((planet) => (
<Block
key=planet.id
id=planet.id
name=planet.englishName
dateDiscovered=planet.discoveryDate
mass=planet.mass.massValue
massExp=planet.mass.massExponent
image=planet.image // <-- pass planet.image
/>
))
</div>
);
【讨论】:
【参考方案5】:我会将图像添加到行星数组中,然后完全删除图像数组。
在这些方面...
if(planets)
planets.map(planet =>getImages(planet.englishName))
,[])
您的getImages
函数正在获取图像并将其存储在images
中
但是由于您已经通过行星进行映射以获取行星名称,因此不要将这些图像存储在单独的变量中,而是将它们返回/存储在行星数组中。
也许是这样的......
if(planets)
planets.map(planet =>
const image = getImages(planet.englishName)
return ...planet, image
)
,[])
所以现在image = ???
这一行是image = planet.image
也许用一个useEffect
来做这一切......
const getPlanets = async() =>
const response = await fetch('https://api.le-systeme-solaire.net/rest/bodies')
const data = await data.json()
const planets = data.bodies.filter(planet =>planet.isPlanet && planet.name.indexOf('1') === -1)
return planets
const getImages = async (name) =>
const response = await axios.get('https://images-api.nasa.gov/search', params:q: name)
const images = response.concat(res.data.collection.items[0].links[0].href)
return images
useEffect(()=>
getPlanets()
.then(planets => Promise.all(planets.map(async (planet) =>
const image = await getImages(planet.englishName)
return ...planet, image
)))
.then(planets => setPlanets(planets))
,[])
*注意我没有测试上面的代码,但希望接近你需要的。
【讨论】:
【参考方案6】:import React, useState, useEffect from 'react';
import './App.css';
import axios from 'axios'
import Block from "./Block"
function App()
const [planets, setPlanets] = useState([])
const [images, setImages] =useState([])
const getPlanets = async()=>
const data = await fetch
('https://api.le-systeme-solaire.net/rest/bodies') //Await for first fetch promise to resolve
const planets = await(data.json()) //Await for data.json to resolve and save this planets
setPlanets(planets.bodies.filter
(planet =>planet.isPlanet && planet.name.indexOf('1')===-1))
useEffect(()=>
getPlanets();
,[])
useEffect(() =>
async function fetchAllImages()
const allImages = [];
for await (const planet of planets)
const data = await axios.get('https://images-api.nasa.gov/search',
params:
q: planet.englishName
)
const res = await data.data.collection.items[0].links[0].href
allImages.push(res);
setImages(allImages);
fetchAllImages();
, [planets])
console.log(images)
return (
<div className="App">
planets.map((planet,index) =>
(<Block
key = planet.id
id = planet.id
name = planet.englishName
dateDiscovered = planet.discoveryDate
mass = planet.mass.massValue
massExp = planet.mass.massExponent
image = images[index]
/>))
</div>
);
export default App;
【讨论】:
感谢大家的帮助。结果证明这是正确创建图像数组和使用索引进行映射的组合。以上是关于同时处理两个API的主要内容,如果未能解决你的问题,请参考以下文章
CountDownLatchCyclicBarrierSemaphore多线程协助操作API