如何通过按钮过滤两个不同API返回的影视数据?
如何实现电影/电视剧内容的切换过滤功能(双API数据源)
我想给项目加个按钮过滤功能:点「电视剧」按钮显示剧集内容,点「电影」按钮显示对应内容。目前数据来自两个不同的API调用,我已经有过滤单个数组属性的功能,但没法直接复用。想问下能不能把两类数据合并到同一数组后按属性过滤,或者有没有更优的解决方案?
我的API调用代码如下:
function App() { // State const [kidsMovies, setKidsMovies] = useState([]) const [kidsTv, setKidsTv] = useState([]) // API URL const kidsMovieURL = 'https://api.themoviedb.org/3/discover/movie?api_key=&certification_country=US&certification.lte=G&with_genres=16&include_adult=false&sort_by=popularity.desc'; const kidsTvURL = 'https://api.themoviedb.org/3/tv/popular?api_key=&language=en-US&page=1&with_genres=16&include_adult=false&sort_by=popularity.desc'; // Async function to fetch API async function getMoviesData (kidsMovieURL, kidsTvUrl) { await fetch(kidsMovieURL).then(res => res.json()).then(data => setKidsMovies(data.results)) await fetch(kidsTvUrl).then(res => res.json()).then(data => setKidsTv(data.results)) } // Use Effect useEffect(() => { getMoviesData(kidsMovieURL, kidsTvURL); }, []) }
解决方案
方案一:合并为带类型标记的统一数组(推荐复用现有过滤逻辑)
如果想复用你已有的单数组过滤功能,最直接的方式是给两类数据加上统一的类型标记,合并成一个数组,再通过状态控制要显示的类型:
- 修改状态结构,用一个数组存储所有媒体内容,再加一个状态控制当前激活的类型:
const [mediaItems, setMediaItems] = useState([]); const [activeType, setActiveType] = useState('movie'); // 默认显示电影
- 优化API请求(改成并行请求提升效率),给每条数据添加
type字段后合并:
async function getMediaData() { // 并行发起两个请求,比串行await更快 const [movieRes, tvRes] = await Promise.all([ fetch(kidsMovieURL).then(res => res.json()), fetch(kidsTvURL).then(res => res.json()) ]); // 给电影数据加type标记 const formattedMovies = movieRes.results.map(item => ({ ...item, type: 'movie' })); // 给电视剧数据加type标记 const formattedTv = tvRes.results.map(item => ({ ...item, type: 'tv' })); // 合并成统一数组 setMediaItems([...formattedMovies, ...formattedTv]); } useEffect(() => { getMediaData(); }, []);
- 渲染时根据
activeType过滤,同时可以复用你现有的单数组过滤逻辑:
// 过滤当前要显示的内容 const currentContent = mediaItems.filter(item => item.type === activeType); // 按钮切换逻辑 return ( <div> <button onClick={() => setActiveType('movie')}>电影</button> <button onClick={() => setActiveType('tv')}>电视剧</button> {/* 渲染currentContent */} <div className="content-grid"> {currentContent.map(item => ( // 根据type区分渲染逻辑(如果需要) <div key={item.id} className="media-card"> {item.type === 'movie' ? <h3>{item.title}</h3> : <h3>{item.name}</h3>} {/* 其他内容渲染 */} </div> ))} </div> </div> );
方案二:保留分开的数组,直接切换数据源
如果不需要合并数据,也可以直接通过状态切换要渲染的数组,这种方式更轻量,不需要修改原有数据结构:
- 添加状态控制当前激活的标签:
const [activeTab, setActiveTab] = useState('movie');
- 渲染时根据
activeTab选择对应的数组:
const currentContent = activeTab === 'movie' ? kidsMovies : kidsTv; return ( <div> <button onClick={() => setActiveTab('movie')}>电影</button> <button onClick={() => setActiveTab('tv')}>电视剧</button> <div className="content-grid"> {currentContent.map(item => ( <div key={item.id} className="media-card"> {/* 注意电影用title,电视剧用name,需要区分 */} <h3>{activeTab === 'movie' ? item.title : item.name}</h3> {/* 其他内容渲染 */} </div> ))} </div> </div> );
额外优化建议
- 把API请求改成
Promise.all并行执行,比原来的串行await更高效,减少加载时间; - 可以给按钮添加激活状态样式,让用户知道当前选中的是哪个标签;
- 如果后续需要更复杂的过滤(比如结合类型+其他属性),方案一的统一数组结构会更灵活。
内容的提问来源于stack exchange,提问作者Gavin-walsh
相关产品推荐
相关产品推荐

