3

I am starting to learn React and creating my second project at the moment. I am trying to usi MovieDb API to create a movie search app. Everything is fine when I get the initial list of movies. But onClick on each of the list items I want to show the details of each movie. I have created a few apps like this using vanilla JS and traditional XHR call. This time I am using fetch API which seems straightforward ans simply to use, however when I map through response data to get id of each movie in order to retrieve details separately for each of them I get the full list of details for all the items, which is not the desired effect. I put the list of objects into an array, because after setState in map I was only getting the details for the last element. I know that I am probably doing something wrong within the API call but it might as well be my whole REACT code. I would appreciate any help.

My code

App.js

import React, { Component } from 'react';
import SearchInput from './Components/SearchInput'
import './App.css';

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

      this.state = 
        {
          value: '',
          showComponent: false, 
          results: [],
          images: {},
        };

    this.handleSubmit = this.handleSubmit.bind(this);
    this.handleOnChange = this.handleOnChange.bind(this);
    this.getImages = this.getImages.bind(this);
    this.getData = this.getData.bind(this);
}

ComponentWillMount() {
  this.getImages();
  this.getData();
}

getImages(d) {
  let request = 'https://api.themoviedb.org/3/configuration?api_key=70790634913a5fad270423eb23e97259'
  fetch(request)
    .then((response) => {
        return response.json();
    }).then((data) => {
      this.setState({
        images: data.images
      });
    });
}

  getData() {
    let request = new Request('https://api.themoviedb.org/3/search/movie?api_key=70790634913a5fad270423eb23e97259&query='+this.state.value+'');

    fetch(request)
      .then((response) => {
        return response.json();
      }).then((data) => {               
        this.setState({
          results: data.results
        });             
      });
  }

  handleOnChange(e) {
    this.setState({value: e.target.value})
  }

  handleSubmit(e) {
    e.preventDefault();
    this.getImages();
    this.setState({showComponent: true});
    this.getData();
  }

  render() {
    return (
      <SearchInput handleSubmit={this.handleSubmit} handleOnChange={this.handleOnChange} results={this.state.results} images={this.state.images} value={this.state.value} showComponent={this.state.showComponent}/>
    );
  }
}

export default App;


SearchInput.js

import React, {Component} from 'react';
import MoviesList from './MoviesList';

class SearchInput extends Component {
  render() {
    return(
      <div className='container'>
        <form id='search-form' onSubmit={this.props.handleSubmit}>
          <input value={this.props.value} onChange={this.props.handleOnChange} type='text' placeholder='Search movies, tv shows...' name='search-field' id='search-field' />
          <button type='submit'>Search</button>
        </form>
        <ul>
          {this.props.showComponent ?
              <MoviesList value={this.props.value} results={this.props.results} images={this.props.images}/> : null
          }
        </ul>
      </div>
    )
  }
}

export default SearchInput;

This is the component where I try to fetch details data

MovieList.js

import React, { Component } from 'react';
import MovieDetails from './MovieDetails';

let details = [];

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

    this.state = {
      showComponent: false,
      details: []
    }

    this.showDetails = this.showDetails.bind(this);
    this.getDetails = this.getDetails.bind(this);

  }


  componentDidMount() {
    this.getDetails();
  }

  getDetails() {
    let request = new Request('https://api.themoviedb.org/3/search/movie?api_key=70790634913a5fad270423eb23e97259&query='+this.props.value+'');

    fetch(request)
      .then((response) => {
        return response.json();
      }).then((data) => {    
      data.results.forEach((result, i) => {
        let url = 'https://api.themoviedb.org/3/movie/'+ result.id +'?api_key=70790634913a5fad270423eb23e97259&append_to_response=videos,images';
        return fetch(url)
        .then((response) => {
          return response.json();
        }).then((data) => {
          details.push(data)   
          this.setState({details: details});   
        });
      });   
      console.log(details);
  });
}



  showDetails(id) {
    this.setState({showComponent: true}, () => {
      console.log(this.state.details)
    });
    console.log(this.props.results)
  }

  render() {
    let results;
    let images = this.props.images;

    results = this.props.results.map((result, index) => {
      return(
        <li ref={result.id} id={result.id} key={result.id} onClick={this.showDetails}>
          {result.title}{result.id}
          <img  src={images.base_url +`${images.poster_sizes?images.poster_sizes[0]: 'err'}` + result.backdrop_path} alt=''/>
        </li>
      )
    });

    return (
      <div>
        {results}
        <div>
          {this.state.showComponent ? <MovieDetails details={this.state.details} results={this.props.results}/> : null}
        </div>
      </div>
    )
  }
}

export default MoviesList;

MovieDetails.js

import React, { Component } from 'react';

class MovieDetails extends Component {


  render() {
    let details;
    details = this.props.details.map((detail,index) => {
      if (this.props.results[index].id === detail.id) {
      return(
        <div key={detail.id}>
          {this.props.results[index].id}  {detail.id}
        </div>
      )} else {
        console.log('err')
      }
    });

    return(
      <ul>
        {details}
      </ul>
    )

  }
}

export default MovieDetails;
6
  • I also forgot to add that the state.details are always the same for each search. Every other state changes with a new search but state.details always remains the same Commented Dec 29, 2017 at 19:35
  • just a note, i recommend not including your api key in your posts... Commented Dec 29, 2017 at 20:57
  • Can you clarify what the actual problem is? what is causing the issue? which api call in particular? Also, you should take a look at axios for making API calls on the client side. Commented Dec 29, 2017 at 21:11
  • Completely forgot about the key...thanks for pointing that out Commented Dec 30, 2017 at 7:20
  • I was thinking about AXIOS as I only ever used Jquery or Vanilla JS to make API calls but decided to try fetch API, which seems very similar to AXIOS Commented Dec 30, 2017 at 7:26

2 Answers 2

1

Theres a lot going on here...

//Here you would attach an onclick listener and would fire your "get details about this specific movie function" sending through either, the id, or full result if you wish.

//Then you getDetails, would need to take an argument, (the id) which you could use to fetch one movie.

getDetails(id){
fetch(id)
displayresults, profit
}

results = this.props.results.map((result, index) => {
          return(
            <li onClick={() => this.getDetails(result.id) ref={result.id} id={result.id} key={result.id} onClick={this.showDetails}>
              {result.title}{result.id}
              <img  src={images.base_url +`${images.poster_sizes?images.poster_sizes[0]: 'err'}` + result.backdrop_path} alt=''/>
            </li>
          )
        });
Sign up to request clarification or add additional context in comments.

Comments

0

Thanks for all the answers but I have actually maanged to sort it out with a bit of help from a friend. In my MovieList I returned a new Component called Movie for each component and there I make a call to API fro movie details using each of the movie details from my map function in MovieList component

Movielist

import React, { Component } from 'react';
import Movie from './Movie';

class MoviesList extends Component {
  render() {
    let results;
    if(this.props.results) {
      results = this.props.results.map((result, index) => {
        return(
          <Movie key={result.id} result={result} images={this.props.images}/>
        )
      });
    }

    return (
      <div>
        {results}
      </div>
    )
  }
}

export default MoviesList;

Movie.js

import React, { Component } from 'react';
import MovieDetails from './MovieDetails';

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

    this.state = {
      showComponent: false,
      details: []
    }

    this.showDetails = this.showDetails.bind(this);
    this.getDetails = this.getDetails.bind(this);
  }

  componentDidMount() {
    this.getDetails();
  }

  getDetails() {
    let request = new Request('https://api.themoviedb.org/3/search/movie?api_key=70790634913a5fad270423eb23e97259&query='+this.props.value+'');

    fetch(request)
      .then((response) => {
        return response.json();
      }).then((data) => {    
        let url = 'https://api.themoviedb.org/3/movie/'+ this.props.result.id +'?api_key=70790634913a5fad270423eb23e97259&append_to_response=videos,images';
        return fetch(url)
      }).then((response) => {
          return response.json();
      }).then((data) => { 
          this.setState({details: data});   
      });
}

  showDetails(id) {
    this.setState({showComponent: true}, () => {
      console.log(this.state.details)
    });
  }

  render() {
    return(
      <li ref={this.props.result.id} id={this.props.result.id} key={this.props.result.id} onClick={this.showDetails}>
        {this.props.result.title}
        <img  src={this.props.images.base_url +`${this.props.images.poster_sizes?this.props.images.poster_sizes[0]: 'err'}` + this.props.result.backdrop_path} alt=''/>
        {this.state.showComponent ? <MovieDetails details={this.state.details}/> : null}
      </li>
    )

  }
}


export default Movie;

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.