5

I am building a simple movie catalogue using themoviedb API however I am facing an issue that I am unable to solve. The issue is that the result after fetching is always undefined.

I tried with the method componentWillMount to fetching data and the setting the state inside this method but it does not work. I tried to fetch inside constructor, no result.

This is my code so far

import React, { Component } from 'react';
import Header from './components/Header';
import MovieList from './components/MovieList';
import Footer from './components/Footer';

const MOVIE_API = "http://api.themoviedb.org/3/discover/movie?api_key=72049b7019c79f226fad8eec6e1ee889&language=en-US&sort_by=release_date.desc&include_adult=true&include_video=false&page=2&primary_release_year=2018";

//class
class App extends Component {
  constructor(props){
    super(props);

    this.state = {
      movies: [],
      movieName: ''
    }
  }


  componentWillMount(){
    this.fetchMovie();
  }


//fetching movie
  fetchMovie = () =>{
    const req = new Request(MOVIE_API, {
      method: 'GET',
      cache: 'default'
    });

    fetch(req).then(response =>{
      return response.json();
    }).then(data =>{
      console.log(data); //REF 1;
      this.setState({
        movies: data
      });
    }).catch(err => {
      console.log("ERROR: " + err);
    })
  }

  render() {
    return (
      <div className="root">
        <Header />
        <MovieList moviesRes={this.state.movies}/>
        <Footer />

      </div>
    );
  }
}

export default App;

As you can see I called the method componentWillMount to fetch the data but it does not work. It is also noticeable that if I log the data (REF 1) I can see the result (json).

===========================

EDIT

This is the code for MovieList

/*import React, { Component } from 'react';

export default class MovieList extends Component{
    constructor(props){
        super(props);
        this.state = {
            movies: this.props.movieRes
        }
    }
    render(){

        //if result is undefined 
        if(this.state.movieRes === undefined){
            return(
                <h1>Loading...</h1>
            );
        }else{
            return(
                <ul>
                {this.state.movieRes.map((movie, index)=>{
                    return (
                        <li key={index}>{movie.title}</li>
                    );
                })}
                </ul>
            );
        }
    }
}*/

=================

update child code

import React, { Component } from 'react';

export default class MovieList extends Component{

    render(){
        const { movieRes = [] } = this.props; // we are assigning a default prop here of an empty array.
        return(
            <ul>
                {
                    //return movie from array
                    movieRes.map((movie, index)=>{
                        return (
                            <li key={index}>
                                {movie.id}
                            </li>
                        );
                    })
                }
            </ul>
        );
    }
}

In this I way I suppress the error, but still it is not working. From what I learnt, React should render as soon as it detect changes but for some reason it not the case.

IMAGE

As you can see from the image when I am passing the array from parent component to the child component the array length is 20 but in the child component the array length seems to be 0

===================

Solution

I changed the component from class to a const and pass to it the array and everything went smooth. Here is the final code:

import React from 'react';

const MovieList = ({movies}) =>{
    if(!movies){
        return <h1>Loading...</h1>
    }
    return (
        <ul>
            {
                movies.map((movie, index) => {
                    return (
                        <li key={index}>
                            <p>{movie.title}</p>
                        </li>
                    )
                })
            }
        </ul>
    );

}

export default MovieList;
5
  • 1
    Can you please give us the error you get? It would also help if you'll show us how the response is structured like. Commented Jan 27, 2018 at 21:04
  • Apologise, I do not get any error. It is the variable movies that does not get any value even after fetching data it keeps an empty array. Commented Jan 27, 2018 at 21:12
  • Are you sure your response is an array? Maybe the response is structured like {movies: []} and then you have to get data.movies. Commented Jan 27, 2018 at 21:17
  • Whoa why are you putting movieRes in state? Just read it from props. That's your problem. It gets set in the state when it's empty during the constructor and nothing updates it. You don't need to copy stuff from props to state. Just read it from this.state in the render method. Commented Jan 27, 2018 at 23:10
  • Did as you said but it does not work, with the conditional render I do not get the result, without the conditional render I get error Commented Jan 27, 2018 at 23:19

1 Answer 1

6

Originally I misunderstood your issue but after re-reading it I noticed that you defined movies as an array in your constructor.

Without an actual error message, I'm going to assume that MovieList is expecting an array for it's prop movieRes and you're probably then trying to do something like .map or a loop to render the movies.

However, the API you're using doesn't return an array. It returns an object with an array key'd under results. So, I changed it to access data.results when doing setState.

//fetching movie
  fetchMovie = () =>{
    const req = new Request(MOVIE_API, {
      method: 'GET',
      cache: 'default'
    });

    fetch(req).then(response =>{
      return response.json();
    }).then(data =>{
      console.log(data);
      this.setState({
        movies: data.results // <-- change made here.
      });
    }).catch(err => {
      console.log("ERROR: " + err);
    })
  }

Here's a working JSFiddle:

https://jsfiddle.net/patrickgordon/69z2wepo/99513/

EDIT: In the child component, instead of assigning props to state, just use props and default props.

import React, { Component } from 'react';

export default class MovieList extends Component{
    render(){
        const { movieRes = [] } = this.props; // we are assigning a default prop here of an empty array.
        return(
            <ul>
                {movieRes.map((movie, index)=>{
                    return (
                        <li key={index}>{movie.title}</li>
                    );
                })}
            </ul>
        );
    }
}
Sign up to request clarification or add additional context in comments.

11 Comments

This does work inside inside the parent component, if I pass as a props to the child component and I try to render I get this error "TypeError: Cannot read property 'map' of undefined",
In the child what are you trying to do a .map on? Can we see that code ?
Thank you for your quick reply, please find the code above.
Changed the code as above and finally I don't get any error, however it does not render anything. One thing I noticed, using the react developer tool I see that when I am passing the array (from parent to child) its length is 20 but if I click to the child the array length results to be 0; I was looking over the react docs but could not find anything in regards
@kd12345 then your initial prop or state is not set properly. try initialising the state as an empty array or pass a prop as an empty array as a default
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.