1

On my Home component, on initial load, I loop through an object of URLs, and use Promise.all to make sure they all resolve at the same time. I construct an object, and push it into state. At the start of this I have loading: true, then set to false when done pushing that object into state:

Home Component:

class Home extends Component {
  state = {
    searchTerm: null,
    movies: {
      trending: {},
      topRated: {},
      nowPlaying: {},
      upcoming: {}
    },
    loading: false
  };
componentDidMount() {
    this.getInitalMovies();       
  }
getInitalMovies = () => {
    const API_KEY = process.env.REACT_APP_API_KEY;
    //set loading to true
    this.setState({ loading: true });
    //create an object with all movie URLs
    const allMovieURLs = {
      trending: `https://api.themoviedb.org/3/trending/movie/day?api_key=${API_KEY}`,
      topRated: `https://api.themoviedb.org/3/movie/top_rated?api_key=${API_KEY}&language=en-US&page=1`,
      nowPlaying: `https://api.themoviedb.org/3/movie/now_playing?api_key=${API_KEY}&language=en-US&page=1`,
      upcoming: `https://api.themoviedb.org/3/movie/upcoming?api_key=${API_KEY}&language=en-US&page=1`
    };

    //break down the movieURL object into entries, fetch the URL, and reassign entries with actual data
    //encapsulate within a Promise.all to ensure they all resolve at the same time.
    const moviePromises = Promise.all(
      Object.entries(allMovieURLs).map(entry => {
        const [key, url] = entry;
        return fetch(url).then(res => res.json().then(data => [key, data]));
      })
    );
    //with the returned promise from Promise.all, reconstruct the array of entries back into an object with relevant key pair values
    const movies = moviePromises.then(movieArr => {
      const dataObj = {};
      for (const [movie, movieData] of movieArr) {
        dataObj[movie] = movieData;
      }
      return dataObj;
    });
    //with the returned object, push it into current state, then turn off loading
    movies.then(movieObj =>
      this.setState({ movies: movieObj, loading: false })
    );
  };
 render() {
    const { movies } = this.state;
    return (
      <div className='App'>
        <Header
          submitHandler={this.submitHandler}
          changeHandler={this.changeHandler}
        />
        <HeroImage />
        {this.state.loading ? <Loader /> : <MovieDisplay movies={movies} />}
      </div>
    );
  }

MovieDisplay Component:

export default class MovieDisplay extends Component {
  render() {
    const { movies } = this.props;
    return (
      <div>
        <MovieRow movies={movies.trending.results} movieType='trending' />
        <MovieRow movies={movies.topRated.results} movieType='top rated' />
        <MovieRow movies={movies.nowPlaying.results} movieType='now playing' />
        <MovieRow movies={movies.upcoming.results} movieType='upcoming' />
      </div>
    );
  }
}

MovieRow Component:

export default class MovieRow extends Component {
  render() {
    const { movieType, movies } = this.props;
    return (
      <div>
        <div className='row-title'>{movieType}</div>
        {console.log(movies)} //This part seems to somehow mount even when conditional rendering says it shouldn't!
        <Slider {...settings} />
      </div>
    );
  }
}

I then have the body do a conditional render like so, so that if the loading is complete (loading: false), then my MovieDisplay component should render, otherwise it's still loading, so show the Loader component.

I confimed that this part is working (if I search the React Devtools for Loader when loading: false it does not exist, but MovieDisplay does exist.

I'm passing down a data object via props from Home > MovieDisplay > MovieRow, and then looping through the array to display more components.

However, on initial load, it seems the MovieRow (last, nested child component) is somehow being mounted for a quick second, because in the console it's logging 4 undefined statements briefly, before resolving with the proper data.

Main question: If the Parent Component is not rendered to the DOM, then the child components inside of the Parent should also not be rendered, right?

Secondary question: Is it possible that all the components in my app are rendering briefly for a second on initial load, despite having a conditional in the render() function? That's the only thing I can think of that's causing this.

Example: If MovieDisplay is not rendered, then everything inside of it like MovieRow should also not be rendered, correct?

Hope this isn't too confusing...please let me know if I need to edit my problem or elaborate.

1
  • I think <MovieDisplay /> 's render function will get called regardless of conditional. If you don't want it's render function to get called, then wrap in a lambda and conditionally invoke it. Commented Mar 5, 2019 at 6:09

2 Answers 2

1

.then does not resolve a promise. It lets you get the value after the promise was resolved

This is because of the asynchronous nature of JS. Initially, when componentDidMount is called, you set loading = true.

Before the promise is completed(loading = true) react renders the HOME component, this is the reason it calls MovieDisplay component.

Try adding an extra condition where you call MovieDisplay

 {this.state.loading && "check your data is filled in movies object" ? <Loader /> : <MovieDisplay movies={movies} />}
Sign up to request clarification or add additional context in comments.

1 Comment

So your answer wasn't exactly working, but I found out the issue because you pointed out the asynchronous nature of the Promise call I made in componentDidMount. My conditional, for a millisecond, was not changing to true, because all of my code ran before my Promise.all finished. Thank you!
1

Can you try this:

{this.state.loading && <Loader />} 
{!this.state.loading && <MovieDisplay movies={movies} />}

Comments

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.