Search code examples
reactjscomponentsreact-propshigher-order-functions

Passing props through to component React


I'm having trouble passing my props through in React and rendering them on my page. I want to map through my movies variable from my App.js pass the props of movie (Title, Poster, Price} to my MovieComponent.js so I can render them on the page.

function App() {
  const [filmWorld, setFilmWorld] = useState([]);
  const [cinemaWorld, setCinemaWorld] = useState([]);

  useEffect(() => {
    const theaters = ["cinema", "film"];
    theaters.forEach((theater) => {
      async function getTheater() {
        const data = await api.getMoviesData(theater);
        if (data.Provider === "Film World") {
          setFilmWorld(data);
        } else {
          setCinemaWorld(data);
        }
      }
      getTheater();
    });
  }, []);

  const movies = useMemo(() => {
    if (!filmWorld.Provider) return [];
    return filmWorld.Movies.map((movie, index) => ({
      ...movie,
      cinemaWorldPrice:
        cinemaWorld.Provider && cinemaWorld.Movies[index]?.Price,
    }));
  }, [filmWorld, cinemaWorld]);

  return (
    <Container>
      <Header>
        <AppName>
          <MovieImage src={movieicon1} />
          Prince's Theatre
        </AppName>
      </Header>
      <MovieListContainer>
        {movies.map((movie, index) => (
          <MovieComponent key={index} movie={movie} />
        ))}

        <MovieComponent />
      </MovieListContainer>
    </Container>
  );
}

export default App; 

originally I had all the code underneath function App() { to return in my MovieComponent and could render in the movie component.

This is my Movie component code:

const MovieComponent = (props) => {
  const { Poster, Price, Title } = props.movie;
  return (
    <MovieContainer>
      <CoverImage src={Poster} alt="" />
      <MovieName>{Title}</MovieName>

      <InfoColumn>
        <MovieInfo>FilmWorld: ${Price}</MovieInfo>
        <MovieInfo>CinemaWorld: ${Price}</MovieInfo>
      </InfoColumn>
    </MovieContainer>
  );
};

export default MovieComponent;

The last working code I had was when the functions and map were in my MovieComponent file this is a copy of the old working code:

const MovieComponent = () => {
  const [filmWorld, setFilmWorld] = useState([]);
  const [cinemaWorld, setCinemaWorld] = useState([]);

  useEffect(() => {
    const theaters = ["cinema", "film"];
    theaters.forEach((theater) => {
      async function getTheater() {
        const data = await api.getMoviesData(theater);
        if (data.Provider === "Film World") {
          setFilmWorld(data);
        } else {
          setCinemaWorld(data);
        }
      }
      getTheater();
    });
  }, []);

  const movies = useMemo(() => {
    if (!filmWorld.Provider) return [];
    return filmWorld.Movies.map((movie, index) => ({
      ...movie,
      cinemaWorldPrice:
        cinemaWorld.Provider && cinemaWorld.Movies[index]?.Price,
    }));
  }, [filmWorld, cinemaWorld]);

  return (
    <MovieContainer>
      {movies.map((movie, index) => (
        <div className="movies" key={index}>
          <MovieName>{movie.Title}</MovieName>
          <CoverImage src={movie.Poster} alt={movie.Title} />

          <InfoColumn>
            <MovieInfo>
              Filmworld Price: ${Number(movie.Price).toFixed(2)}
            </MovieInfo>
            <MovieInfo>
              Cinemaworld Price: ${Number(movie.cinemaWorldPrice).toFixed(2)}
            </MovieInfo>
          </InfoColumn>
        </div>
      ))}
    </MovieContainer>
  );
};

export default MovieComponent;

But this was effecting my stylings so I feel like if I call the functions and map in App and call the props in MovieComponent my app will render correctly again.

I'm receiving errors like this:

Uncaught TypeError: Cannot destructure property 'Poster' of 'props.movie' as it is undefined.

Solution

  • Why are you calling MovieComponent a second time after the map function inside of your App.js file without passing any props to it? try removing that and let me know if that helps.

    Like this:

    function App() {
      const [filmWorld, setFilmWorld] = useState([]);
      const [cinemaWorld, setCinemaWorld] = useState([]);
    
      useEffect(() => {
        const theaters = ["cinema", "film"];
        theaters.forEach((theater) => {
          async function getTheater() {
            const data = await api.getMoviesData(theater);
            if (data.Provider === "Film World") {
              setFilmWorld(data);
            } else {
              setCinemaWorld(data);
            }
          }
          getTheater();
        });
      }, []);
    
      const movies = useMemo(() => {
        if (!filmWorld.Provider) return [];
        return filmWorld.Movies.map((movie, index) => ({
          ...movie,
          cinemaWorldPrice:
            cinemaWorld.Provider && cinemaWorld.Movies[index]?.Price,
        }));
      }, [filmWorld, cinemaWorld]);
    
      return (
        <Container>
          <Header>
            <AppName>
              <MovieImage src={movieicon1} />
              Prince's Theatre
            </AppName>
          </Header>
          <MovieListContainer>
            {movies.map((movie, index) => (
              <MovieComponent key={index} movie={movie} />
            ))}
          </MovieListContainer>
        </Container>
      );
    }
    
    export default App;