0

I'm new to React and I'm following a tutotial to learn how to fetch data from a public API.

I can render the "parent" items like the Title in this case, however I can't find a way to render the (nested) child items like Ratings. This is the error I'm getting "TypeError: movie.Ratings is undefined".

Here's the request outcome in JSON:

enter image description here

Here's my React code:

import React, { useEffect, useState } from "react";
import "./App.css";

function App() {

  const [movie, getMovie] = useState([]);

  useEffect(() => {
    const getData = async () => {
      const response = await fetch("https://www.omdbapi.com/?apikey=XXXXXXXX&t=Parasite");
      const json = await response.json();
      getMovie(json);
    };

    getData();

  }, []);

  return (
    <div className="App">
      <ul>
        <li>{movie.Title}</li>
        {movie.Ratings.map(Score => (
          <li>{Score.Source}</li>
        ))}
      </ul>
    </div>
  );

}

export default App
4
  • do you have some error? or what result do you want to get? Commented Jun 5, 2020 at 12:20
  • but you're rendering the ratings Commented Jun 5, 2020 at 12:20
  • I'm sorry, I forgot to include the error. This is the error I'm getting "TypeError: movie.Ratings is undefined". I'll update the question. Commented Jun 5, 2020 at 12:24
  • you need to render the component if movie && movie.Ratings are defined Commented Jun 5, 2020 at 12:25

2 Answers 2

2

You can add ? (optional chaining) to only to map if there is movie

 {movie.Ratings?.map(Score => (
      <>
      <li>{Score.Source}</li>
      <li>{Score.Value}</li>
      </>
    ))}
Sign up to request clarification or add additional context in comments.

6 Comments

Thank you Dipesh. As mentioned, I'm new to React but this looks very elegant and simpler. This worked but how would you render Value as well, under each correspoding Source using this method?
Nevermind Dipesh, I just figured it out. I can simply use "<li>{Score.Source}: {Score.Value}</li>".
yeah.You can do in either way as you prefer :)
I think simply adding "?" (optional chaining) to only to map if there is movie as you suggested in your answer was the easiest and cleanest way to solve this problem. I'm choosing your answer. Thank you Dipesh.
Great to help you brother :)
|
1

There are a few things I notice

const [movie, getMovie] = useState([]); You are initializing this as an array of movie it should be const [movie, getMovie] = useState({});

function App() {

  const [movie, getMovie] = useState({});

  useEffect(() => {
    const getData = async () => {
      const response = await fetch("https://www.omdbapi.com/?apikey=XXXXXXXX&t=Parasite");
      const json = await response.json();
      getMovie(json);
    };

    getData();

  }, []);

  if (!movie.Ratings || movie.Ratings.length === 0) return null;

  return (
    <div className="App">
       <ul>
         <li>{movie.Title}</li>
         {movie.Ratings.map(score => (
           <li>{score.Source}</li>
         ))}
      </ul>
    </div>
  );
}

Or the return block can be written this way too without the if

return (
    <div className="App">
       <ul>
         <li>{movie.Title}</li>
         {movie.Ratings && movie.Ratings.map(score => (
           <li>{score.Source}</li>
         ))}
      </ul>
    </div>
  );

3 Comments

Thanks for your help Hendrix. I just tried your amends and now I'm getting "TypeError: movie.map is not a function".
Thank you, this works. But does that means I'll have to repeat "if (!movie.Ratings || movie.Ratings.length === 0) return null;" for every nested items I want to render?
I’ve added an alternative way too, depends how you wish to do it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.