My react code is looping around my data and only viewing the last value. What am I doing incorrectly?

Viewed 39

I have this API link https://swapi.dev/api/planets and I want to return the film titles for each planet

For example:

Planet: Tatooine

Films: A New Hope, Return of the Jedi, The Phantom Menace, Attack of the Clones, Revenge of the Sith

I have two components, Planets and Films. Planets fetches the titles of the planets from the API link I mentioned above. Films uses a props called films from Planets component to return films that were filmed on the planet https links. I want to return the film titles for each planet, however the result I get is: Planet: Tatooine Films: Revenge of the Sith

PS: I'm a beginner in reactjs

Here is my planet component code:

import Films from "./Films";
import { useState, useEffect } from "react";

const month = [
  "Jan",
  "Feb",
  "Mar",
  "Apr",
  "May",
  "Jun",
  "Jul",
  "Aug",
  "Sept",
  "Oct",
  "Nov",
  "Dec",
];
export default function Planets() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetch("https://swapi.dev/api/planets")
      .then((response) => {
        if (!response.ok) {
          throw new Error(
            `This is an HTTP error: The status is ${response.status}`
          );
        }
        return response.json();
      })
      .then((actualData) => {
        setData(actualData.results);
        setError(null);
      })
      .catch((err) => {
        setError(err.message);
        setData(null);
      })
      .finally(() => {
        setLoading(false);
      });
  }, []);

  return (
    <div>
      {loading && <div>A moment please...</div>}
      {error && (
        <div>{`There is a problem fetching the post data ${error}`}</div>
      )}
      <div>
        {data &&
          data.map(({ name, created, films, climate }) => (
            <div key={"key" + Math.random()} className="planet__container">
              <div className="planet__dates">
                <div>
                  <p>{new Date(created).getFullYear()}</p>
                </div>
                <div>
                  <p>
                    {new Date(created).getDate()}{" "}
                    {month[new Date(created).getMonth()]},{" "}
                    {new Date(created).getHours()}:
                    {new Date(created).getMinutes()}:
                    {new Date(created).getSeconds()}
                  </p>
                </div>
              </div>
              <div className="planet__info">
                <div>
                  {/* <img src=""/> */}
                  <h3>{name}</h3>
                  <Films films={films} />
                </div>
                <div>
                  <p>{climate}</p>
                </div>
              </div>
            </div>
          ))}
      </div>
    </div>
  );
}

And here is my Films component code:

import { useState, useEffect } from "react";
function Films(props) {
  var films = String(props.films).replaceAll(",", "");
  const [data, setData] = useState("");
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  const tempArray = films.split("https://").splice(1);
  useEffect(() => {
    tempArray.map((url) =>
      fetch("https://" + url)
        .then((response) => {
          if (!response.ok) {
            throw new Error(
              `This is an HTTP error: The status is ${response.status}`
            );
          }
          return response.json();
        })
        .then((actualData) => {
          setData(actualData.title);
          setError(null);
        })
        .catch((err) => {
          setError(err.message);
          setData(null);
        })
        .finally(() => {
          setLoading(false);
        })
    );
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);
  return (
    <div>
      {loading && <div>A moment please...</div>}
      {error && (
        <div>{`There is a problem fetching the post data ${error}`}</div>
      )}
      <div>
        <div>
          <p>{data}</p>
        </div>
      </div>
    </div>
  );
}
export default Films;

and this is my app.js code:

import Planets from "./Components/Planets";

function App() {
  return <Planets />;
}

export default App;
1 Answers

You are calling fetch in a loop, but setting the title setData(actualData.title); in this line overwrites it, so at the end you get only one title.

Your Films component must be like this:

import { useState, useEffect } from "react";
function Films({films}) {
  const fetchAll = async (urls) => {
    const res = await Promise.all(urls.map((u) => fetch(u)));
    const jsons = await Promise.all(res.map((r) => r.json()));
    return jsons
  };

  const [filmInfos, setFilmInfos] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetchAll(films)
      .then((results) => {
        setFilmInfos(results);
        setError(null);
      })
      .catch((err) => {
        setError(err.message);
        setFilmInfos(null);
      })
      .finally(() => {
        setLoading(false);
      });
  }, [films]);

  return (
    <div>
      {loading && <div>A moment please...</div>}
      {error && (
        <div>{`There is a problem fetching the post data ${error}`}</div>
      )}
      <div>
        <div>
          {filmInfos && filmInfos.map(info => <p key={info.title}>{info.title}</p>)}
        </div>
      </div>
    </div>
  );
}
export default Films;

Codesandbox

Related