Reputation: 13
I am trying to get a list of movies from an array that I have. I am looping over the array to put the title and poster on the screen. But even though the loop only happens once, it keeps making the same three api calls over and over again. I am really new to React and thought that it should only make a new call if something changes?
import React from 'react';
import $ from 'jquery';
var movieArray = ['Tarzan','1o1uyry29ddz', 'tt0120855',
'Close Encounters Of The Third Kind', 'g3hl6ewv9b7h', 'tt0075860',
'10,000 BC', 'tngmycvr418q', 'tt0443649'
];
export class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
name: '',
poster: '',
backdrop: '',
genre: '',
release: '',
description: ''
};
}
componentDidUpdate(id){
let self = this;
let url = 'https://api.themoviedb.org/3/find/'
let apiKey = '?api_key=<my-api-key>'
let language = '&language=en-US'
let imdb = '&external_source=imdb_id'
$.ajax({
type: 'GET',
url: url + id + apiKey + language + imdb
})
.done(function(data) {
self.setState({
name: data.title,
poster: data.poster_path,
backdrop: data.backdrop_path,
genre: data.genre_ids,
release: data.release_data,
description: data.overview
});
})
.fail(function(jqXhr) {
console.log('Failed to Connect to TMDB Server');
});
}
movieLoad(){
var arrayLength = movieArray.length;
var movieList = [];
var url = "http://image.tmdb.org/t/p/w185//"+this.poster ;
for (var i = 0; i < arrayLength-2; i++) {
this.componentDidUpdate(movieArray[i+2]);
console.log(this.title);
movieList.push(
<div>
<h1>{this.title}</h1>
<img src= {url} />
</div>
);
i = i + 2;
}
return movieList;
}
render() {
return (
<div>
{this.movieLoad()}
</div>
);
}
}
export default Home;
Upvotes: 0
Views: 3198
Reputation: 15780
The problem here is the way you're calling movieLoad
in your render
function - each time it renders, it's going to call movieLoad
, which calls componentDidUpdate
, which will update the component state via setState
, which will cause the component to re-render, which will call movieLoad
, .... you can see where this is going.
The key is to update your state independently of the render
method. React provides a couple of ways to do that:
in response to events - for example, if you have a button to click, an event is fired that calls an onClick
event handler where your state is updated. Then the render
method is called by React to update the component.
when the component is first loaded - in the componentDidMount
method. You can call setState
here and React will call render
when it's ready
when the component receives new properties from a parent - in the componentWillReceiveProps
method. Then you can update the state with the new props via setState
and render
will be called by React
For a detailed look at these, check out the State and Lifecycle section of the React docs.
The key is that when you are updating the component state with the setState
method, you let React take care of the rendering and don't try to change the state while it's rendering.
Upvotes: 1
Reputation: 1056
You have to write separate asynchronous function to call Ajax requests. It's very critical mistake to call lifecycle methods(componentDidUpdate etc.) on purpose. Just extract the Ajax call to another function and change your state by calling
this.setState({
name: data.title,
poster: data.poster_path,
backdrop: data.backdrop_path,
genre: data.genre_ids,
release: data.release_data,
description: data.overview
});
If it's still confusing to you take a look at Ajax Request's in React
Edited: I have assumed that you are going request multiple times. If you need to call your request only one time, you are free to use it in componentDidMount() but without calling it recursively or calling it from elsewhere again.
Upvotes: 1
Reputation: 6261
your issue is with this code right here.
componentDidUpdate(id){
let self = this;
let url = 'https://api.themoviedb.org/3/find/'
let apiKey = '?api_key=7d7a79eb6ca4f02c996a7f8f0795293e'
let language = '&language=en-US'
let imdb = '&external_source=imdb_id'
$.ajax({
type: 'GET',
url: url + id + apiKey + language + imdb
})
.done(function(data) {
self.setState({
name: data.title,
poster: data.poster_path,
backdrop: data.backdrop_path,
genre: data.genre_ids,
release: data.release_data,
description: data.overview
});
})
.fail(function(jqXhr) {
console.log('Failed to Connect to TMDB Server');
});
Every time you cal setState
componentDidUpdate
will fire again, and since you are calling setState
inside of didUpdate, you are getting an infinite loop.
You have 2 options to fix this. First, you can move your ajax request to the didMount lifecycle method which only fires one time after the component has mounted. The other option, and this is assuming you have a reason to use didupdate, would be to have some check whether anything has in fact changed, and only call a setState
when there is a reason to.
For most common use cases, option 1 is the way to go.
Upvotes: 0