如何从TMDB API获取并渲染3条电影数据?TS类型校验求助
问题解决:无法渲染TMDB热门电影数据 + TypeScript类型校验优化
一、渲染失败的核心原因及修复
你的代码无法渲染数据,主要存在两个关键问题:
1. map回调未返回元素
在topThree.map的箭头函数中,你使用大括号包裹逻辑但没有显式returnJSX元素,导致每个循环迭代都返回undefined,页面自然没有内容。
修复方式二选一:
- 去掉大括号,用括号包裹JSX(箭头函数隐式返回):
{topThree.map((movie) => ( <> <h1>{movie.id}</h1> <p>{movie.title}</p> </> ))}
- 保留大括号,添加
return关键字:
{topThree.map((movie) => { return ( <> <h1>{movie.id}</h1> <p>{movie.title}</p> </> ); })}
2. 多余的Object.entries处理
TMDB返回的data.results本身就是电影对象数组,不需要用Object.entries转成键值对数组,直接截取前3项即可:
// 原代码 setTopThree(Object.entries(data.results).slice(0,3).map(entry => entry[1])); // 修复后 setTopThree(data.results.slice(0, 3));
额外优化:利用loading状态
你定义了loading但未使用,可添加加载状态提示,避免页面空白:
useEffect(()=>{ const url = `https://api.themoviedb.org/3/movie/popular?api_key=${process.env.MOVIE_API}`; axios(url) .then(({data}) => { setTopThree(data.results.slice(0, 3)); setLoading(false); // 请求成功后结束加载 }) .catch(err => { console.log(err.message); setLoading(false); // 请求失败也结束加载 }); },[]); // 修改return逻辑 if (loading) return <div>加载中...</div>; if (!topThree) return <div>暂无数据</div>; return ( <> {topThree.map((movie) => ( <> <h1>{movie.id}</h1> <p>{movie.title}</p> </> ))} <div className="absolute top-[15%] left-[10%]"></div> </> );
二、TypeScript类型校验优化
你已经定义了基础接口,接下来可以进一步完善并应用到代码中,替换any类型:
1. 完善接口(匹配TMDB返回字段)
根据TMDB官方API规范,调整接口字段的可选性(比如title是必返回字段,不需要加?):
interface IMovie { id: number; original_title: string; title: string; poster_path: string | null; backdrop_path: string | null; genre_ids: number[]; // 可根据需求添加其他字段,比如vote_average、release_date等 }
2. 指定State类型
将topThree和movies的State类型从any[] | null替换为IMovie[] | null:
const [movies, setMovies] = useState<IMovie[] | null>(null); const [topThree, setTopThree] = useState<IMovie[] | null>(null);
3. 给Axios请求指定返回类型
让Axios明确知道返回数据的结构,避免类型推断错误:
axios.get<{ results: IMovie[] }>(url) .then(({data}) => { setTopThree(data.results.slice(0, 3)); setLoading(false); })
修复后的完整代码
import { useEffect, useState } from 'react'; import axios from 'axios'; interface IMovie { id: number; original_title: string; title: string; poster_path: string | null; backdrop_path: string | null; genre_ids: number[]; } function Carousel() { const [movies, setMovies] = useState<IMovie[] | null>(null); const [topThree, setTopThree] = useState<IMovie[] | null>(null); const [loading, setLoading] = useState(true); useEffect(()=>{ const url = `https://api.themoviedb.org/3/movie/popular?api_key=${process.env.MOVIE_API}`; axios.get<{ results: IMovie[] }>(url) .then(({data}) => { setTopThree(data.results.slice(0, 3)); setLoading(false); }) .catch(err => { console.log(err.message); setLoading(false); }); },[]); if (loading) return <div>加载中...</div>; if (!topThree) return <div>暂无数据</div>; return ( <> {topThree.map((movie) => ( <> <h1>{movie.id}</h1> <p>{movie.title}</p> </> ))} <div className="absolute top-[15%] left-[10%]"></div> </> ); } export default Carousel;
内容的提问来源于stack exchange,提问作者Damien Sullivan
相关产品推荐
相关产品推荐

