reactjs - De ce nu pot să setez un array la datele API folosind useState()?


Deci, am o aplicație care folosește API-ul de Filme. Fac o cerere API, apoi transmit aceste date într-un array folosind hook-ul useState, practic codul meu arată astfel:

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

Deci practic, când rulez aplicația, primesc un alert cu o eroare. Am încercat să redenumesc useState, astfel încât să fie diferit de props în componenta <Hero>, și apoi am putut să trec datele într-un array. Dar când fac asta cu [movies, setMovies] nu funcționează. Așadar, presupun că problema este undeva la transmiterea props sau type MovieType, dar nu reușesc să-mi dau seama exact care ar putea fi problema.

Editare: o eroare pe care o primesc în try catch:

TypeError: movies.map is not a function

Am movies.map în componenta Container, care preia filmele de la Hero, care le ia din App:

const Container = ({movies}: MovieProps) => {
  return (
    <div className="container">
      {movies.map((movie) =>(
          <MovieItem movie={movie} key={movie.title}/>
      ))}
    </div>
  );
};

Nu știu de ce movies.map nu este o funcție dacă movies este practic un array.

Răspuns #1

Trebuie să adaugi „await fetchMovies” în loc de doar „fetchMovies”, dar pentru că nu poți face useEffect asincron, încearcă ceva de genul acesta...

 useEffect(() =>{
      async function foo(){
        await fetchMovies();
     }
      foo();
  }, []);

Sper că funcționează!

Răspunsul #2

Problema este că componenta Container încearcă să itereze peste movies înainte ca fetchMovies să fi terminat de obținut datele. Practic, încerci să iterezi peste un array gol. Pentru a evidenția acest lucru și în scopuri de depanare viitoare, include un console.log(movies) în Container.

Pentru a remedia, includeți pur și simplu movies.length ca verificare înainte de a parcurge datele cu map:

const Container = ({movies}: MovieProps) => {
  return (
    <div className="container">
      {movies.length && movies.map((movie) =>(
          <MovieItem movie={movie} key={movie.title}/>
      ))}
    </div>
  );
};