React电影应用:实现动态搜索栏以按需渲染匹配电影卡片
解决方案:实现React电影应用的动态搜索功能
要实现实时搜索匹配电影的功能,我们需要解决两个核心问题:管理搜索输入的状态和基于输入过滤电影数据,同时还要注意不要丢失原始的电影数据(否则清空搜索框时无法恢复全部内容)。下面是具体的修改步骤和完整代码:
第一步:重构App组件,分离原始数据与过滤后数据
首先,我们需要在App组件中维护两个状态:
originalMovies:保存从API获取的所有原始电影数据,确保搜索时不会丢失源数据filteredMovies:保存根据搜索关键词过滤后的结果,用于渲染电影卡片
同时添加一个回调函数,让Search组件可以通知App组件更新搜索关键词,进而执行过滤逻辑。
修改后的App组件代码:
import React, { useState, useEffect } from "react"; import "./App.css"; import Logo from "../components/Logo"; import Search from "../components/Search"; import Add_movie_button from "../components/Add_movie_button"; import Random_movie_button from "../components/Random_movie_button"; import Movie_card from "../components/Movie_card"; import axios from "axios"; const BASE_URL = "https://api.themoviedb.org/3/movie/"; const API_KEY = "4bcd155b9b8734cb8559319cdbfaf62f"; function App() { // 存储所有原始电影数据 const [originalMovies, setOriginalMovies] = useState([]); // 存储过滤后的电影数据,用于页面渲染 const [filteredMovies, setFilteredMovies] = useState([]); useEffect(() => { axios .get("http://localhost:5000") .then(function (response) { const movies = response.data.movies; return Promise.all( movies.map((movie) => axios.get( `${BASE_URL}${movie.movieid}?api_key=${API_KEY}&language=fr` ) ) ); }) .then((responses) => { const movieData = responses.map((response) => ({ Genres: response.data.genres, Overview: response.data.overview, Poster: response.data.poster_path, Company: response.data.production_companies, Release: response.data.release_date, Title: response.data.title, Id: response.data.id, })); // 初始化时同时设置原始数据和过滤后数据 setOriginalMovies(movieData); setFilteredMovies(movieData); }); }, []); // 处理搜索关键词变化的回调函数 const handleSearchChange = (query) => { if (!query.trim()) { // 搜索框为空时,显示全部电影 setFilteredMovies(originalMovies); return; } // 过滤标题以搜索词开头的电影(不区分大小写,提升用户体验) const filteredResults = originalMovies.filter(movie => movie.Title.toLowerCase().startsWith(query.toLowerCase()) ); setFilteredMovies(filteredResults); }; return ( <div className="App"> <div className="Header"> <Logo /> </div> <div className="Menu"> {/* 将搜索回调传递给Search组件 */} <Search onSearchChange={handleSearchChange} /> <Add_movie_button /> <Random_movie_button data={filteredMovies} /> </div> <div className="Movies"> {/* 使用过滤后的电影数据渲染卡片 */} {filteredMovies.map((movie) => ( <Movie_card key={movie.Id} data={movie} /> ))} </div> </div> ); } export default App;
第二步:完善Search组件,管理输入状态并触发搜索
在Search组件中,我们需要使用useState来管理输入框的值,同时在输入变化时调用父组件传递的回调函数,将当前搜索词传递给App组件执行过滤。
修改后的Search组件代码:
import React, { useState } from "react"; import "./style.css"; const Search = ({ onSearchChange }) => { // 管理搜索输入框的状态 const [searchQuery, setSearchQuery] = useState(""); const handleInputChange = (event) => { const inputValue = event.target.value; // 更新组件内部的搜索状态 setSearchQuery(inputValue); // 通知父组件执行过滤逻辑 onSearchChange(inputValue); }; return ( <div className="Search"> <input type="search" id="Search_input" placeholder="Rechercher un film ..." value={searchQuery} onChange={handleInputChange} /> </div> ); }; export default Search;
关键细节说明
为什么分离原始数据与过滤数据?
如果直接修改原有的movieinfos状态,当用户清空搜索框时,我们无法恢复最初的全部电影数据。分离两个状态可以确保原始数据始终被保留,随时可以复用。不区分大小写的搜索
使用toLowerCase()将电影标题和搜索词统一转换为小写,这样用户输入"har"、"Har"或者"HAR"都能匹配到正确的结果,提升了搜索的友好性。更可靠的key值
将Movie_card的key从movie.Title改为movie.Id,因为电影标题可能存在重复,但ID是唯一的,符合React对key的要求。
内容的提问来源于stack exchange,提问作者user16697052
相关产品推荐
相关产品推荐

