Reputation: 402
In React, I'm using Axios to map an array to output a list of movie names that are pulling from the MovieDB API. It connects to the MovieDB just fine, however, I get the following error in the console:
Uncaught TypeError: this.state.movies.map is not a function
I believe this is preventing the movie list from outputting to the browser.
Codesandbox link is here.
Here's the SearchBar component where the code lies:
import React, { Component } from "react";
import TextField from "@material-ui/core/TextField";
import axios from "axios";
import "../SearchBar/_search-bar.scss";
class SearchBar extends Component {
state = {
userSearchTerm: "",
movies: []
};
// When user types, match the value to state
onInputChange = e => {
this.setState({ userSearchTerm: e.target.value });
};
// On submitting the input, grab the API
onInputSubmit = e => {
e.preventDefault();
const movieName = this.state.userSearchTerm;
const KEY = "XXXXXXXXXX";
const searchQuery = `https://api.themoviedb.org/3/search/movie?api_key=${KEY}&language=en-US&query=${movieName}&page=10`;
axios.get(searchQuery).then(res => {
this.setState({ movies: res.data });
});
};
render() {
return (
<div>
<form onSubmit={this.onInputSubmit}>
<TextField
label="Search for a movie and hit enter..."
margin="normal"
className="search-bar"
onChange={this.onInputChange}
/>
</form>
<ul>
{this.state.movies.map(movie => (
<li key={movie.id}>{movie.results.title}</li>
))}
</ul>
</div>
);
}
}
export default SearchBar;
On a side note, I tested out this same code, but with a different API and it worked just fine. Is there something wrong with the API itself or the this.state.movies.map?
Upvotes: 0
Views: 5327
Reputation: 439
The API you are using is returning an object with "results" being the key you are looking for. If you update your setState to this.setState({ movies: res.data.results });
you should get what you are looking for.
As a side note I would guard your map function with something like {Array.isArray(this.state.movies) && this.state.movies.map(movie => (...
this will conditionally render the output only once movies
is set in state and is an array.
Upvotes: 4
Reputation: 1267
A working code:
import React, { Component } from "react";
import TextField from "@material-ui/core/TextField";
import axios from "axios";
import "../SearchBar/_search-bar.scss";
class SearchBar extends Component {
state = {
userSearchTerm: "",
movies: []
};
// When user types, match the value to state
onInputChange = e => {
this.setState({ userSearchTerm: e.target.value });
};
// On submitting the input, grab the API
onInputSubmit = e => {
e.preventDefault();
const movieName = this.state.userSearchTerm;
const KEY = "XXXXXX";
const searchQuery = 'https://api.themoviedb.org/3/search/movie?api_key=${KEY}&language=en-US&query=${movieName}&page=10';
axios.get(searchQuery).then(res => {
console.log("res is ------", res)
this.setState({ movies: res.data.results });
});
};
render() {
return (
<div>
<form onSubmit={this.onInputSubmit}>
<TextField
label="Search for a movie and hit enter..."
margin="normal"
className="search-bar"
onChange={this.onInputChange}
/>
</form>
<ul>
{this.state.movies.map(movie => (
<li key={movie.id}>{movie.original_title}</li>
))}
</ul>
</div>
);
}
}
export default SearchBar;
You should use this.setState({ movies: res.data.results });
and <li key={movie.id}>{movie.original_title}</li>
Let me know if it works.
Upvotes: 3
Reputation: 872
You need to change the setState call to this:
this.setState({ movies: res.data.results });
The response is not an array, it is an object like this:
{
"page": 10,
"total_results": 136643,
"total_pages": 6833,
"results": [
{
"vote_count": 110,
"id": 13189,
"video": false,
"vote_average": 7.3,
"title": "A Christmas Carol",
"popularity": 6.52,
"poster_path": "/m3T3iLdE6J5PrqvvP0XNHBvM2bm.jpg",
"original_language": "en",
"original_title": "A Christmas Carol",
"genre_ids": [
18,
10751,
14,
10770
],
"backdrop_path": "/gaTpxTYQMGoagtMVYK8F7SjqTGM.jpg",
"adult": false,
"overview": "An old bitter miser who makes excuses for his uncaring nature learns real compassion when three ghosts visit him on Christmas Eve.",
"release_date": "1984-12-17"
},
{
"vote_count": 419,
"id": 12103,
"video": false,
"vote_average": 6.1,
"title": "Don't Say a Word",
"popularity": 9.995,
"poster_path": "/qx3hgW9MqxsEEFjx4eSbpp1Fe2l.jpg",
"original_language": "en",
"original_title": "Don't Say a Word",
"genre_ids": [
53
],
"backdrop_path": "/AaOtoMzqWJPSNXPRKwbvqf6MbKo.jpg",
"adult": false,
"overview": "When the daughter of a psychiatrist is kidnapped, he's horrified to discover that the abductors' demand is that he break through to a post traumatic stress disorder suffering young woman who knows a secret..",
"release_date": "2001-09-28"
}
]
}
Upvotes: 0