尽管有条件声明,组件仍以某种方式呈现

时间:2019-03-05 06:06:16

标签: javascript reactjs

在我的Home组件上,在初始加载时,我遍历了URL对象,并使用Promise.all确保它们同时解析。我构造一个对象,并将其推入状态。首先,我有loading: true,然后在将对象推入状态时设置为false

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组件:

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组件:

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>
    );
  }
}

然后让主体像这样进行条件渲染,以便如果加载完成(loading: false),则我的MovieDisplay组件应渲染,否则它仍在加载,因此显示{ {1}}组件。

我确认这部分工作正常(如果我在Loader确实不存在,但Loader 存在的情况下,在React Devtools中搜索loading: false确实存在

我正在通过道具从MovieDisplay> Home> MovieDisplay传递数据对象,然后循环遍历数组以显示更多组件。

但是,在初始加载时,似乎MovieRow(最后一个嵌套的子组件)以某种方式很快挂载了,因为在控制台中,它在解决之前简要记录了4条MovieRow语句带有正确的数据。

主要问题:如果未将父级组件呈现给DOM,那么父级内部的子组件也不应呈现,对吗?

第二个问题:尽管undefined函数中有条件,但我的应用程序中的所有组件是否都有可能在初始加载时短暂地呈现一秒钟?这是我唯一想到的原因。

示例:如果未渲染render(),那么也不应渲染其中的所有内容,例如MovieDisplay,对吗?

希望这不太令人困惑...请让我知道我是否需要编辑问题或进行详细说明。

2 个答案:

答案 0 :(得分:1)

您能尝试一下吗?

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

答案 1 :(得分:1)

.then无法解决承诺。它使您可以在诺言兑现后获得价值

这是由于JS的异步特性。最初,在调用componentDidMount时,将loading设置为true。

在完成承诺(加载= true)之前,react会渲染HOME组件,这就是它调用MovieDisplay组件的原因。

尝试在调用MovieDisplay的地方添加一个额外条件

 {this.state.loading && "check your data is filled in movies object" ? <Loader /> : <MovieDisplay movies={movies} />}