【问题标题】:Handle two APIs at the same time同时处理两个API
【发布时间】: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)

标签: javascript reactjs api fetch


【解决方案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;
            

            【讨论】:

            • 感谢大家的帮助。结果证明这是正确创建图像数组和使用索引进行映射的组合。
            猜你喜欢
            • 2017-06-10
            • 1970-01-01
            • 1970-01-01
            • 2018-11-16
            • 1970-01-01
            • 2014-04-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多