reactjs - Varför kan jag inte sätta en array till API-data med useState()?
Så jag har en app som använder Movies API. Jag gör en API-förfrågan, sedan skickar jag denna data till en array med hjälp av useState-hooken, i princip ser min kod ut som följande:
const App = () => {
type MovieType = { //declaring type
rate: string,
title: string,
tagline: string,
date: string,
};
interface MovieProps { //extending an interface with MovieType
movies: MovieType[],
}
const [movies, setMovies] = useState<MovieType[]>([]); //useState for setting an array to data from api
useEffect(() =>{
fetchMovies();
}, [])
async function fetchMovies() { //function for fetching movies
try{
let apikey = '{api_key}';
let url: string = 'https://api.themoviedb.org/3/discover/movie?sort_by=popularity.desc&api_key=';
url = url + apikey;
const response = await axios.get<[MovieType]>(url);
setMovies(response.data);
}catch(e){
alert('Error');
}
}
return (
<div className="App">
<Header/>
<Hero movies={movies}/>
</div>
);
}
Så i princip, när jag kör appen, får jag en varning med ett fel. Jag har försökt byta namn på useState, så att det skiljer sig från props i <Hero>-komponenten, och då kunde jag skicka data till en array. Men när jag gör det med [movies, setMovies] fungerar det inte. Så jag antar att problemet är någonstans i att skicka props eller type MovieType, men jag kan inte lista ut exakt vad problemet kan vara.
Redigera: ett fel jag får i try catch:
TypeError: movies.map is not a function
Jag har movies.map i Container-komponenten, som får filmer från Hero, som får dem från App:
const Container = ({movies}: MovieProps) => {
return (
<div className="container">
{movies.map((movie) =>(
<MovieItem movie={movie} key={movie.title}/>
))}
</div>
);
};
Jag vet inte varför movies.map inte är en funktion om movies i princip är en array.
Svar #1
Du måste lägga till "await fetchMovies" istället för bara "fetchMovies", men eftersom du inte kan göra useEffect asynkron, försök med något som detta...
useEffect(() =>{
async function foo(){
await fetchMovies();
}
foo();
}, []);
Förhoppningsvis fungerar det!
Svar #2
Problemet är att Container-komponenten försöker iterera över movies innan fetchMovies har slutat hämta datan. I grund och botten försöker du iterera över en tom array. För att visa detta, och för framtida felsökningsändamål, inkludera en console.log(movies) i Container.
För att fixa, inkludera helt enkelt movies.length som en kontroll innan du mappar över datan:
const Container = ({movies}: MovieProps) => {
return (
<div className="container">
{movies.length && movies.map((movie) =>(
<MovieItem movie={movie} key={movie.title}/>
))}
</div>
);
};
