reactjstypescriptfetch-api

How to fetch and display related data in React using fetch and TypeScript?


I'm trying to build a simple movie listing page in React with TypeScript. Each movie has a title, director, release year, and genre. I'm fetching data from an API and displaying it in a responsive grid layout.

Here's a simplified version of what I'm working with:

The images are stored locally in the public/ folder, named after the movie title.

How can I correctly display the fetched movie data in my React component?

I tried using useEffect to fetch the movie data from my local API at http://localhost:3000/api/movies, and it seems to work fine in terms of data loading. Here's the fetch part I wrote:

useEffect(() => {
  const fetchMovies = async () => {
    try {
      const response = await fetch("http://localhost:3000/api/movies");
      if (!response.ok) {
        setError("Failed to load movies (" + response.statusText + ")");
        return;
      }
      const data = await response.json();
      setMovies(data);
      setError("");
    } catch (err) {
      setError(`Failed to load movies: ${err}`);
    }
  };

  fetchMovies();
}, []);

Solution

  • First import:

    import { useEffect, useState } from "react";
    

    Set the type:

    type Movie = {
      id: number;
      title: string;
      director: string;
      release_year: number;
      genre: string;
    };
    

    Function component:

    const MovieList = () => {
      const [movies, setMovies] = useState<Movie[]>([]);
      const [error, setError] = useState("");
    

    The fetch part you created:

      useEffect(() => {
        const fetchMovies = async () => {
          try {
            const response = await fetch("http://localhost:3000/api/movies");
            if (!response.ok) {
              setError("Failed to load movies (" + response.statusText + ")");
              return;
            }
            const data = await response.json();
            setMovies(data);
            setError("");
          } catch (err) {
            setError(`Failed to load movies: ${err}`);
          }
        };
    
        fetchMovies();
      }, []);
    

    How to display it

      return (
        <section className="col-sm-12 container-fluid">
          <h2>Movie List</h2>
    
          {error && <p style={{ color: "red" }}>{error}</p>}
          {movies.length === 0 && <p>No movies available.</p>}
    
          <div className="row">
            {movies.map((movie) => (
              <div
                className="col-sm-12 col-md-6 col-lg-4 border p-3 mb-3"
                key={movie.id}
              >
                <h3>{movie.title}</h3>
                <p>
                  Director: {movie.director}
                </p>
                <p>
                  Release Year: {movie.release_year}
                </p>
                <p>
                  Genre:{movie.genre}
                </p>
                <img
                  src={`/${movie.title}.jpg`}
                  alt={movie.title}
                  className="img-fluid mb-3"
                />
    
              </div>
            ))}
          </div>
        </section>
      );
    };
    
    export default MovieList;
    

    App.tsx:

    import "./styles.css";
    import "bootstrap/dist/css/bootstrap.min.css";
    import MovieList from "./pages/List";
    
    export default function App() {
      return (
        <>
          <header className="text-center">
            <h1>Hello CodeSandbox</h1>
          </header>
    
          <main className="App container">
            <h2>Start editing to see some magic happen!</h2>
            <MovieList />
    
          </main>
    
          <footer className="text-center">
            <h3>Start editing to see some magic happen!</h3>
          </footer>
        </>
      );
    }
    
    
    

    Sandbox link if you want to test it