Реагировать на проблему MovieDB API.Установка this.setState дважды ломает мой компонент - PullRequest
0 голосов
/ 05 апреля 2019

Я следовал учебному пособию по YouTube, используя API MovieDB с React. Я могу искать фильмы и получать название, описание и изображение фильма. Я хочу добавить возможность воспроизведения трейлера на YouTube. Я успешно получил идентификаторы YouTube и сохранил их. У меня проблемы с отображением. Если я раскомментирую в моем App.js

this.setState({ rows: videoRows });

Тогда видео на YouTube работают. Но мой заголовок, описание и изображение фильма не определены, и наоборот.

App.js

import React, { Component } from "react";
import "./App.css";
import MovieRow from "./MovieRow.js";

import $ from "jquery";

class App extends Component {
  constructor(props) {
    super(props);

    this.state = {};
    this.performSearch("woman");
  }

  performSearch(searchTerm) {
    // console.log("perform search");
    const API_KEY = "625914798003ef54176364f32c232968";
    const urlString = `https://api.themoviedb.org/3/search/movie?api_key=${API_KEY}&query=${searchTerm}`;
    const urlVideoString = `https://api.themoviedb.org/3/movie/297762/videos?api_key=${API_KEY}&language=en-US`;

    //fetch generic info
    $.ajax({
      url: urlString,
      success: searchResults => {
        console.log("fetch basic success");
        const results = searchResults.results;
        var videoRows = [];
        var movieRows = [];
        // call next ajax function
        $.ajax({
          url: urlVideoString,
          success: searchResults => {
            console.log("fetch Youtube video key success");
            const results = searchResults.results;

            results.forEach(movie => {
              movie.video_src = movie.key;
              console.log(movie.video_src);

              var videoRow = <MovieRow key={movie.id} movie={movie} />;
              videoRows.push(videoRow);
            });


            //If I run this line below it will break 
            //my generic basic info(title, movie description, and picture) , 
            //but it makes the youtube player work
            // this.setState({ rows: videoRows });
          },



          error: (xhr, status, err) => {
            console.log("failed video fetch");
          }
        });
        results.forEach(movie => {
          movie.poster_src =
            "https://image.tmdb.org/t/p/w185" + movie.poster_path;
          console.log(movie.poster_path);

          const movieRow = <MovieRow key={movie.id} movie={movie} />;
          movieRows.push(movieRow);
        });

        this.setState({ rows: movieRows });
      },

      error: (xhr, status, err) => {
        console.log("failed fetch");
      }
    });
  }
  searchChangeHandler(event) {
    console.log(event.target.value);
    const boundObject = this;
    const searchTerm = event.target.value;
    boundObject.performSearch(searchTerm);
  }
  render() {
    return (
      <div>
        <table className="titleBar">
          <tbody>
            <tr>
              <td>
                <img alt="app icon" width="100" src="green_app_icon.svg" />
              </td>
              <td width="8" />
              <td>
                <h1>MoviesDB Search</h1>
              </td>
            </tr>
          </tbody>
        </table>
        <input
          style={{
            fontSize: 24,
            display: "block",
            width: "99%",
            paddingTop: 8,
            paddingBottom: 8,
            paddingLeft: 16
          }}
          onChange={this.searchChangeHandler.bind(this)}
          placeholder="Search for movie by title..."
        />
        {this.state.rows}
      </div>
    );
  }
}

export default App;

MovieRow.js

import React from "react";
import YouTube from "react-youtube";

class MovieRow extends React.Component {
  constructor(props) {
    super(props);
    this.state = {};
  }
  viewMovie() {
    const url = "https://www.themoviedb.org/movie/" + this.props.movie.id;
    window.location.href = url;
  }
  viewTrailer() {
    //const trailerURL = "https://www.youtube.com/watch?v=1Q8fG0TtVAY";
  }
  _onReady(event) {
    // access to player in all event handlers via event.target
    event.target.pauseVideo();
  }
  render() {
    const opts = {
      height: "390",
      width: "50%",
      playerVars: {
        // https://developers.google.com/youtube/player_parameters
        autoplay: 1
      }
    };

    return (
      <table key={this.props.movie.id}>
        <tbody>
          <tr>
            <td>
              <img alt="poster" width="180" src={this.props.movie.poster_src} />
            </td>
            <td>
              <h1>src {this.props.movie.video_src}</h1>
              <h3>{this.props.movie.title}</h3>
              <p>{this.props.movie.overview}</p>

              <YouTube
                videoId={this.props.movie.video_src}
                opts={opts}
                onReady={this._onReady}
              />
              <input
                className="btn btn-primary"
                type="button"
                onClick={this.viewTrailer.bind(this)}
                value="Play Trailer"
              />
              <input
                className="btn btn-primary"
                type="button"
                onClick={this.viewMovie.bind(this)}
                value="View"
              />
            </td>
          </tr>
        </tbody>
      </table>
    );
  }
}

export default MovieRow;

1 Ответ

0 голосов
/ 05 апреля 2019

Я вижу здесь много проблем. Во-первых, это состояние строки не инициализируется. Вы всегда должны инициализировать состояние в конструкторе

this.state = {
  row: []
};

Другая проблема, которую я видел, заключается в том, что вы не должны хранить компоненты в состоянии. Посмотреть это

Состояние должно содержать данные, которые обработчики событий компонента могут изменить, чтобы вызвать обновление пользовательского интерфейса. В реальных приложениях эти данные имеют тенденцию быть очень маленькими и JSON-сериализуемыми. При создании компонента с состоянием подумайте о минимально возможном представлении его состояния и сохраняйте эти свойства только в этом. Внутри render () просто вычислите любую другую информацию, которая вам нужна, основываясь на этом состоянии. Вы обнаружите, что обдумывание и написание приложений таким образом ведет к созданию наиболее правильного приложения, поскольку добавление избыточных или вычисляемых значений в состояние означает, что вам нужно явно сохранять их синхронизацию, а не полагаться на то, что React будет их вычислять для вас.

Вместо этого вы можете переписать ваше состояние как

this.state = {
   movies: []
}

А внутри вашего ajax-запроса

// Change these lines to 
results.forEach(movie => {
  movie.video_src = movie.key;
  console.log(movie.video_src);

  var videoRow = <MovieRow key={movie.id} movie={movie} />;
  videoRows.push(videoRow);
});

// To this
results.forEach(movie => {
  movie.video_src = movie.key;
  videoRows.push(movie);
});

this.setState({ movies: videoRows });

И, наконец, внутри вашего метода рендеринга зациклите все фильмы в вашем состоянии и вернитесь ваш компонент MovieRow

{this.state.movies.map(movie => <MovieRow key={movie.id} movie={movie}/>)}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...