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>
  );
};