How to wait for fetch to complete before rendering page in React.js

11,719

Solution 1

Your loading and state management is actually fine - running map on an empty array will not result in an error.

Your issue is actually with the data you are getting back. I checked the response of the URL you are using and it returns an object with the data and paging details like this:

{
  data: [
    // The gif array
  ],
  pagination: {...},
  meta: {...}
}

Using map on this object will give you an error. The gif array is in the data property which you should use - e.g. instead of:

this.setState({gifs})

You can use:

this.setState({gifs: gifs.data})

Solution 2

You have to check first if gifs array is not empty. When the setState is done, render will trigger again, and this time there will be gifs to map.

    let gifArray = '';

    if (this.state.gifs.length > 0) {
        gifArray = this.state.gifs.map((gif) => {
          return <GifCard key={gif.name} gif={gif}/>
        })
    }
Share:
11,719

Related videos on Youtube

Tomas Engquist
Author by

Tomas Engquist

Updated on June 04, 2022

Comments

  • Tomas Engquist
    Tomas Engquist about 2 years

    In this React component, I'm trying to fetch data from the GIPHY API and render it in another component. The fetch is working correctly, but this.state.gifs.map returns an error because it runs before the fetch is complete and the state is set. I have tried using Hooks with async/await but that did not seem to work either. How can I create my gifArray after the state is set so I'm not trying to run .map on an empty array.

    import React, {Component} from 'react'
    import GifCard from './gifCard.js'
    import './App.css'
    
    export default class GifContainer extends Component{
    
      state = {
        gifs: []
      }
    
      componentDidMount(){
        fetch('http://api.giphy.com/v1/gifs/search?q=ryan+gosling&api_key=KnzVMdxReB873Hngy23QGKAJh6WtUnmz&limit=5')
        .then(res => res.json())
        .then(gifs => {
          this.setState({gifs})
        })
      }
    
    
      render(){
        const gifArray = this.state.gifs.map((gif) => {
          return <GifCard key={gif.name} gif={gif}/>
        })
        return(
          <div>
            <h1 id="heading">Gif Search</h1>
            <div id='gifContainer'>
              {gifArray}
            </div>
          </div>
    
        )}
    
    }
    
    • Jayce444
      Jayce444 over 4 years
      You don't wait until the fetch is done before rendering, you render some loading indicator in the mean time, or if you don't care about UX you can just return null; if the fetch hasn't finished yet. You can store the status of the fetch in the state
  • smashed-potatoes
    smashed-potatoes over 4 years
    I wouldn't recommend doing this - it adds unnecessary logic. Calling map on an empty array will result in an empty array which is fine. React will render an empty array the same as an empty string (as nothing) so removing the if you will receive the same output.