javascript 从另一个API数据获取API URL ID无法正常工作

lyr7nygr  于 2023-05-27  发布在  Java
关注(0)|答案(2)|浏览(152)

在我的小react项目中,我需要在后续的api调用中使用一个API调用的id。我可以访问第一次调用的数据,但不知道如何在第二次调用中使用它。我尝试使用字符串文字来访问所有的id,这样URL就可以直接从其他API中选择每个id,但它只是返回随机的ID。
下面是我的代码

import React, { Component } from "react";
import axios from "axios";
export default class Cat extends Component {
   state = {
   imagedata: [],
   data: [],
   CatWeight: "",
   CatMetric: "",

     }
   
componentDidMount(){
   this.fetchCountryData();
   this.fetchImageUrl();
}     

  fetchCountryData = async () => {
    const url = "https://api.thecatapi.com/v1/breeds";
    try {
      const response = await axios.get(url);
      const data = await response.data;
     console.log(data)
      this.setState({
        data,
      });
    } catch (error) {
      console.log(error);
    }
  };

  fetchImageUrl = async () =>{
    
    // This is the Place I'm having issue with. The line below. where imgurl becomes https://api.thecatapi.com/v1/images/search?breed_id=char as an example
    // The id is coming from the First API id's
  const imgurl = `https://api.thecatapi.com/v1/images/search?breed_id=${this.state.data.map((item) => { return item.id })} ` 

 try {
    const response = await axios.get(imgurl);
    const imagedata = await response.data;
    console.log(imagedata)
    this.setState({
        imagedata,
    });
  } catch (error) {
    console.log(error);
  }
};

   
 render() {
   return (
     <div>
      {
            this.state.imagedata.map((item, id) =>{
            return <ul key={id}>{item.id}</ul>
            })
        
      }
      
     </div>
   )
 }
}
k10s72fa

k10s72fa1#

我不知 prop 体的API,但看起来那个端点只需要一个id。通过使用map,你给它一个id数组。您可能需要为每个ID进行单独的API调用。

nle07wnf

nle07wnf2#

:根据评论意见对答案进行了重大更新。)
你的原稿有一处排印错误。我不知道这是否只是在StackOverflow中,或者它是否也在代码中失败。但搜索网址看起来像

https://api.thecatapi.com/v1/images/search?breed_ids=ebur

breed_ids,复数,不是breed_id。此外,它只需要一个单一的品种ID,而不是它们的列表,所以你需要为每个单独的调用。
在大多数情况下(64/67),图像URL已经在响应中,没有理由再次获取它。因此,我们可以只获取少数缺失的元素,并使用Promise.all合并它们来处理输出。这里有一个技术,它不试图使用你的React设置,而是一个简单的innerHTML在一些文本操作之上,并使用原生的fetch而不是axios

fetch('https://api.thecatapi.com/v1/breeds')
  .then (resp => resp.json())
  .then (breeds => breeds .map (
    breed => 'image' in breed && 'url' in breed.image
      ? Promise .resolve ({name: breed.name, url: breed.image.url})
      : fetch (`https://api.thecatapi.com/v1/images/search?breed_ids=${breed.id}`)
          .then (resp => resp .json ())
          .then (res => ({name: breed.name, url: res[0].url}))
  ))
  .then (xs => Promise.all (xs))
  .then (breeds => breeds.map(
    breed => `<img src="${breed .url}" title="${breed .name}" width="100"/>`
  ).join (''))
  .then (pics => document .getElementById ('cats') .innerHTML = pics)
  .catch (err => console .log (`Error: ${err}`))
<div id="cats"></div>

因为Promise.all在其输入数组中接受标量值和Promises,所以我们不必在Promise中 Package 原始文档中的那些值。而不是

? Promise .resolve ({name: breed.name, url: breed.image.url})

我们可以直接写

? {name: breed.name, url: breed.image.url}

而且它的性能会稍微好一点。但我还是更喜欢写出来的版本,只是出于对一致性的渴望。
另外,如果您在支持optional chaining operator的环境中工作(大多数但不是所有的通用环境),那么

breed => 'image' in breed && 'url' in breed.image

最好写成

breed => breed?.image?.url

更新--分解

一个评论要求代码分解。下面是一个尝试:

fetch('https://api.thecatapi.com/v1/breeds')
  .then (resp => resp.json())

我们首先获取数据并将结果转换为对象。我使用了内置的fetch调用,而不是导入axios,但是我们可以用axios做一些非常类似的事情。
请注意,我们在这里使用的是直接的promise,而不是async-await。这当然可以用aysnc-await风格重写,但是,特别是当我使用Promise.all时,我看不到太多优点。

.then (breeds => breeds .map (

我们从调用中得到的结果是一个数组。我们在该数组上使用Array.prototype.map,将一个品种数组转换为另一个数组,如下一节所示:

breed => 'image' in breed && 'url' in breed.image
      ? Promise .resolve ({name: breed.name, url: breed.image.url})
      : fetch (`https://api.thecatapi.com/v1/images/search?breed_ids=${breed.id}`)
          .then (resp => resp .json ())
          .then (res => ({name: breed.name, url: res[0].url}))
  ))

在这里,我们测试对象是否已经具有我们想要的URL属性。如果是这样,我们返回一个已经解析的Promise,该Promise的对象具有在数组中的breed对象中找到的nameurl属性。如果没有(在我的测试中只有几个),我们为该品种构建图像搜索url,调用fetch,当结果promise解析时,我们将此响应转换为resp .json ()对象,最后从这个对象构建name/url对象。
在条件语句的任一分支中,我们返回一个Promise。这是一个Promises数组。

.then (xs => Promise.all (xs))

我们使用Promise.allname/url对象的Promise数组转换为name/url对象数组的Promise。这个Promise将在我们提供的所有Promises都已解析时解析,它将返回一个包含调用结果的数组。例如,如果我们有这个:

Promise.all([
  new Promise ((res, rej) => setTimeout(res, 2000, 'foo')),
  new Promise ((res, rej) => setTimeout(res, 3000, 'bar')),
  new Promise ((res, rej) => setTimeout(res, 1000, 'baz')),
])

它将解析(在3秒内,当最终的promise解析时)为数组['foo', 'bar', 'baz']。如果我们加上这个:

new Promise ((res, rej) => setTimeout(rej, 2000, 'qux')),

则它将以值'qux'拒绝(在两秒内,当第一个承诺被拒绝时)。
Promise.all是一个真实的的方便。我们现在有一个承诺,当一切成功时,给我们一系列的品种。

.then (breeds => breeds.map(
    breed => `<img src="${breed .url}" title="${breed .name}" width="100"/>`
  ).join (''))
  .then (pics => document .getElementById ('cats') .innerHTML = pics)

这只是创建一个HTML字符串并将其插入到文档中。你需要查阅你的React文档来找到与React等效的异步处理。但应该不难。

.catch (err => console .log (`Error: ${err}`))

最后,如果有一个错误,其中一个Promises无法解决,拒绝原因将出现在这里。你可能也会用React技术来处理这个问题。

相关问题