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();
}, []);
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>
</>
);
}