简体   繁体   中英

Mapping data from different API in one component in react.js?

I'm working on a challenge. My task is to use two APIS: https://api.thecatapi.com/v1/images/search?breed_id=abys and https://api.thecatapi.com/v1/breeds

to display image and description. So far I've got:

 import React, { Component } from 'react' import ReactDOM from 'react-dom' import axios from 'axios' const Cat = ({ cat: { name, weight, life_span, description } }, { image: url }) => { return ( <div className='cat'> <div className='cat_wrapper'> <img src={url} alt="catimage" /> </div> <h3 className='cat_breed'>{name.toUpperCase()}</h3> <div className='country_text'> <span>Weight:{weight.metric}</span> <span>Lifespan: {life_span}</span> <div>Description: {description}</div> </div> </div> ) } class App extends Component { state = { data: [], data2: [] } componentDidMount() { this.fetchCatData() } fetchCatData = async () => { const url = 'https://api.thecatapi.com/v1/breeds' const images = 'https://api.thecatapi.com/v1/images/search?breed_id=abys' try { const response = await axios.get(url) const response2 = await axios.get(images) const data = await response.data const data2 = await response2.data2 this.setState({ data, data2 }) } catch (error) { console.log(error) } } render() { return ( <div className='App'> <div> <p>There are {this.state.data.length} cats in the api</p> <div className='wrapper'> {this.state.data.map((cat, image) => ( <Cat image={this.state.data2.image} cat={cat} key={cat.id} /> ))} </div> </div> </div> ) } } const rootElement = document.getElementById('root') ReactDOM.render(<App />, rootElement)

But it returns an error

× TypeError: Cannot read property 'image' of undefined

How to fix it?

-=EDITED=-

so, now it reads the 'url' key, earlier it was undefined . I managed to display a hardcoded image of a cat, now I wonder how to map all the different images to its proper contents.

 import React, { Component } from 'react' import ReactDOM from 'react-dom' import axios from 'axios' const Cat = ({ cat: { name, weight, life_span, description, url }}) => { return ( <div className='cat'> <div className='cat_wrapper'> <img alt="catimage" src={url} width="50" height="30"/> </div> <h3 className='cat_breed'>{name.toUpperCase()}</h3> <div className='country_text'> <span>Weight:{weight.metric}</span> <span>Lifespan: {life_span}</span> <div>Description: {description}</div> </div> </div> ) } class App extends Component { state = { data: [], data2: [] } componentDidMount() { this.fetchCatData() } fetchCatData = async () => { const url = 'https://api.thecatapi.com/v1/breeds' const images = 'https://api.thecatapi.com/v1/images/search?breed_id=abys' try { const response = await axios.get(url) const response2 = await axios.get(images) const data = await response.data const data2 = await response2.data this.setState({ data, data2 }) } catch (error) { console.log(error) } } render() { return ( <div className='App'> <div> <p>There are {this.state.data.length} cats in the api</p> <div className='wrapper'> {this.state.data.map((cat) => { cat.url = this.state.data2[0].url; return <Cat cat={cat} key={cat.id}/> } )} </div> </div> </div> ) } } const rootElement = document.getElementById('root') ReactDOM.render(<App />, rootElement)

you better first fetch all data cats then, for each cat make a request to fetch its correspondent image for that cat and add an image or url attribute like:

  fetchCatData = async () => {
    const catsDataUrl = 'https://api.thecatapi.com/v1/breeds'
    const searchImgUrl = 'https://api.thecatapi.com/v1/images/search?breed_id='
    try {
      const catsResponse = await axios.get(catsDataUrl)
      const cats = catsResponse.data
      
      await Promise.allSettled(cats.map(async (cat) => {
        const response = await axios.get(`${searchImgUrl}${cat.id}`)
        cat.url = response.data[0].url // data is an array with a single object        
      }))

      this.setState({cats}) // I changed state name for cats to be more semantic
      
    } catch (error) {
      console.log(error)
    }
  }

now you don't need data2, you already have url. fwiw, your error is given the fact that data2 is an array and not an object with image attribute.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM