Alex
Alex

Reputation: 1

React - Fill data before api call?

I tried to call some rest API, but I got some issue.

Uncaught TypeError: Cannot read property 'name' of undefined

So here's my code:

class MovieDetailViewer extends React.Component {
constructor() {
    super();
    this.state = {
        movieResponse: {}, // wont work
        movieResponse: {
            "id": 1,
            "barcode": "000-000-003",
            "name": "Django Unchained",
            "fsk": "FSK_18",
            "lend": false,
            "deleted": false,
            "genre": {
                "id": 1,
                "name": "Western"
            },
            "source": {
                "id": 1,
                "name": "Blu-Ray"
            }
        } // will work
}

componentDidMount() {
    fetch('apiurltogetmovie')
        .then((response) = > response.json())
        .then(responseJson = > {
            this.setState({ movieJsonResponse: responseJson.movie });

        });
}

render() {
    return (
        <div>
            <MovieDetails
                movie={this.state.movieJsonResponse}
            />
        </div>
    );
}
}

class MovieDetails extends React.Component {
render() {
    const movie = this.props.movie;

    return (
        <div>
            <h1>{movie.name}</h1>
            <h2>{movie.gerne.name} - {movie.source.name}</h2>
            <p>
                {movie.comment}
            </p>
        </div>
    )
}
}

It looked like there was a problem with JSON response but if initialize movieResponse with some default JSON it works. At google I cant find any react example where the state is initialize with some value. Whats the best practice here?

So I am not sure why gerne.name is undefinied. If I log the JSON response to console it will be fine.

Upvotes: 0

Views: 79

Answers (2)

Yossi
Yossi

Reputation: 445

Best practices that can be used here:

  1. Use prop-types to force props to be the same type you expect for.
  2. Validate object inner fields, for example: movie && movie.name.
  3. Use conditional render, for example { movie && movie.name && <h1>{movie.name}</h1>}

Upvotes: 0

treyhakanson
treyhakanson

Reputation: 4911

The problem is that before the API call in MovieDetailViewer finishes, MovieDetails is rendered. But, since the response is not available, movieResponse is still equal the initial value, which in this case is an empty object. Thus, when attempting to access movie.genre.name, since movie is empty, genre will be undefined and name unable to be accessed. To fix this, you should only render MovieDetails once the response is available:

class MovieDetailViewer extends React.Component {

    constructor() {
        super();
        this.state = {
            movieResponse: null
        }
    }

    ...

    render() {
        return (this.state.movieJsonResponse) ? (
            <div>
                <MovieDetails movie={this.state.movieJsonResponse} />
            </div>
        ) : (
            <div className="loader">loading...</div>
        );
    }
}

It is worth noting that your check should likely be more thorough than this, and involve another property on the state describing the current status of the query (querying, success, error, etc.)

Upvotes: 2

Related Questions