0

So I access the JSON data and store the values I need to a dict called details and then return it. When I console log from inside the function I am able to see the info/values, but when I console log in the parent function I get all undefined. I want to use the values in details to populate a component in the return function at the end.

import React from "react"
import theMovieDb from  './moviedb.js'

export default function MovieDetails(props){

    const movieDetails = GetMovieDetails(props.id)
    console.log(movieDetails)

    function GetMovieDetails(id) {
        var details = {
            genres: undefined,
            title: undefined,
            imdbID: undefined,
            popularity: undefined,
            releaseDate: undefined,
            posterPath: undefined,
        }

        theMovieDb.movies.getById({
    
            "id" : id
            
        }, function( data ) {
            data = JSON.parse( data );
            details.genres =  data.genres
            details.title =  data.original_title
            details.imdbID =  data.imdb_id
            details.popularity =  data.popularity
            details.releaseDate =  data.poster_path
            details.posterPath =  data.release_date
            console.log(details)

        }, function( err ) {
            console.error(err)
        });

        return(
            details
        );
    }

    return (
        <div className='movie-card-container'>
            <div >
                <h1>Title: {movieDetails.title}</h1>
                <h2>Year Released: 2005 </h2>
                <h2>Genre: Action/Sci-Fi</h2>
                <h3>Run Time: 2h 20m</h3>
            </div>
    
        </div>
    );
}

console logs

  • `theMovieDb.movies.getById` is run asynchronously. It is still running when you return `details` so `details` is not populated until after you return it and log it to the console. This is why your log statement from the parent function hits the console before your log statement from the callback – Ben Borchard Nov 01 '22 at 19:50
  • Normally something like this would be a duplicate of [this](https://stackoverflow.com/q/14220321/328193) (which is still useful for reference here). But since you're using React, I'm hoping to find a better duplicate. In general what you want to do here is *update state* with your data, not *return* it. – David Nov 01 '22 at 19:54

1 Answers1

0

theMovieDb.movies.getById returns a promise which means it will run asynchronously which in turn means your GetMovieDetails call will exit before results are returned.

The most common practice is to set a state variable when the fetch completes successfully.

To do this:

First create your state variable - replace const movieDetails = GetMovieDetails(props.id) with

var [details, setDetails] = useState();

Next wrap the call to fetch data in useEffect (https://reactjs.org/docs/hooks-effect.html). The data only needs to be fetched if our props.id changes we enforce this by including it in the useEffects parameter array.

useEffect(() => GetMovieDetails(props.id), [props.id]);

Then we want to update the state variable when the data is finally returned (on success) from our api.

Replace

function( data ) {
        data = JSON.parse( data );
        details.genres =  data.genres
        details.title =  data.original_title
        details.imdbID =  data.imdb_id
        details.popularity =  data.popularity
        details.releaseDate =  data.poster_path
        details.posterPath =  data.release_date
        console.log(details)

    }

with

function( data ) {
        data = JSON.parse( data );
        setDetails(data)
    }

And finally update the JSX to reference the state variable:

return (
    <div className='movie-card-container'>
        <div >
            <h1>Title: {details?.title}</h1>
            <h2>Year Released: 2005 </h2>
            <h2>Genre: Action/Sci-Fi</h2>
            <h3>Run Time: 2h 20m</h3>
        </div>

    </div>
);

This is the gist of how it works: When the component first loads useEffect is triggered (because of props.id) and the GetMovieDetails function is called which initiates a promise (which is asynchronous) before exiting. When the promise successfully returns, state is updated and this causes the component to reload and the JSX renders the value from state. (note: the details state variable will initially be undefined as we did not specify a default value when defining it).

Leigh.D
  • 463
  • 5
  • 13