最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Undefined value after fetching API, React - Stack Overflow

programmeradmin8浏览0评论

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 ponentWillMount 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 './ponents/Header';
import MovieList from './ponents/MovieList';
import Footer from './ponents/Footer';

const MOVIE_API = ";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: ''
    }
  }


  ponentWillMount(){
    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 ponentWillMount 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 ponent to the child ponent the array length is 20 but in the child ponent the array length seems to be 0

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

Solution

I changed the ponent 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;

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 ponentWillMount 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 './ponents/Header';
import MovieList from './ponents/MovieList';
import Footer from './ponents/Footer';

const MOVIE_API = "http://api.themoviedb/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: ''
    }
  }


  ponentWillMount(){
    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 ponentWillMount 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 ponent to the child ponent the array length is 20 but in the child ponent the array length seems to be 0

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

Solution

I changed the ponent 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;
Share edited Jan 28, 2018 at 1:05 tufailra97 asked Jan 27, 2018 at 20:59 tufailra97tufailra97 571 gold badge1 silver badge7 bronze badges 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. – Tamir Kfir 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. – tufailra97 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. – Tamir Kfir 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. – stone 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 – tufailra97 Commented Jan 27, 2018 at 23:19
Add a ment  | 

1 Answer 1

Reset to default 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/patrickgordon/69z2wepo/99513/

EDIT: In the child ponent, 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>
        );
    }
}
发布评论

评论列表(0)

  1. 暂无评论