React电影搜索功能异常:点击搜索无响应,仅重启后生效
React电影搜索项目OMDb API实时检索问题
问题现象
基于React开发的电影搜索项目,使用OMDb API实现影片检索时,输入影片名称点击搜索按钮后无法实时展示对应结果,仅在重启服务器后才能显示所需内容。曾尝试在useEffect中无限调用API实现实时更新,但受限于API每日1000次的调用限制,该方案不可取。
相关代码
Movies组件
import { useState,useEffect } from 'react' import React from 'react' import MoviesItem from './MoviesItem' const Movies = ({search}) => { const [movie, setMovie] = useState([]) const fetchUserData = async() => { if(search){ const mov=await fetch(`https://www.omdbapi.com/?apikey=35b97ba4&s=${search}`) const res=await mov.json() console.log(res) setMovie(res.Search) } else { const mov=await fetch(`https://www.omdbapi.com/?apikey=35b97ba4&s="jawan"`) const res=await mov.json() console.log(res) setMovie(res.Search) } } useEffect(() => { fetchUserData() // eslint-disable-next-line },[]) return ( <div className='container'> { <div className="row"> {movie.map((m)=>{ return <div className='col md-4'> <MoviesItem title={m.Title} poster={m.Poster}/> </div> })} </div> } </div> ) } export default Movies
Home组件
import React,{useState} from 'react' import Search from './Search' import Movies from './Movies' const Home = () => { const [searchContent, setSearchContent] = useState(''); const handleSearch = (searchTerm) => { setSearchContent(searchTerm); console.log(searchTerm) }; return ( <div className='container'> <Search onSearch={handleSearch}/> <Movies search={searchContent}/> </div> ) } export default Home
问题根源
Movies组件的useEffect依赖项为空数组[],仅会在组件首次挂载时执行一次fetchUserData。当Home组件的searchContent更新并传递给Movies的search props时,由于useEffect未监听search的变化,不会触发新的API请求,因此无法实时更新搜索结果。
修复方案
- 更新useEffect依赖项:将
search添加到useEffect的依赖数组中,确保每次search值变化时重新请求API:
useEffect(() => { fetchUserData() }, [search])
- 添加防抖优化:为避免用户快速输入时频繁调用API(触发每日调用限制),添加防抖逻辑,延迟执行请求:
useEffect(() => { // 设置300ms延迟,用户停止输入后再请求 const timer = setTimeout(() => { fetchUserData() }, 300) // 组件卸载或search变化时清理定时器 return () => clearTimeout(timer) }, [search])
- 完善错误处理与边界情况:处理API返回无结果或请求失败的情况,避免页面报错:
const fetchUserData = async () => { try { const searchQuery = search || "jawan" const mov = await fetch(`https://www.omdbapi.com/?apikey=35b97ba4&s=${searchQuery}`) const res = await mov.json() if (res.Response === "True") { setMovie(res.Search) } else { setMovie([]) // 无结果时清空列表 console.log('检索失败:', res.Error) } } catch (err) { console.error('网络请求失败:', err) setMovie([]) } }
- 添加列表key属性:为React列表渲染的元素添加唯一
key,避免控制台警告:
{movie.map((m) => ( <div className='col md-4' key={m.imdbID}> <MoviesItem title={m.Title} poster={m.Poster} /> </div> ))}
最终修改后的Movies组件
import { useState, useEffect } from 'react' import React from 'react' import MoviesItem from './MoviesItem' const Movies = ({ search }) => { const [movie, setMovie] = useState([]) const fetchUserData = async () => { try { const searchQuery = search || "jawan" const mov = await fetch(`https://www.omdbapi.com/?apikey=35b97ba4&s=${searchQuery}`) const res = await mov.json() if (res.Response === "True") { setMovie(res.Search) } else { setMovie([]) console.log('检索失败:', res.Error) } } catch (err) { console.error('网络请求失败:', err) setMovie([]) } } useEffect(() => { const timer = setTimeout(() => { fetchUserData() }, 300) return () => clearTimeout(timer) }, [search]) return ( <div className='container'> <div className="row"> {movie.map((m) => ( <div className='col md-4' key={m.imdbID}> <MoviesItem title={m.Title} poster={m.Poster} /> </div> ))} </div> </div> ) } export default Movies
内容的提问来源于stack exchange,提问作者SCoder
相关产品推荐
相关产品推荐

