React搜索功能输入框值设置问题求助:useState与useRef均失效
React搜索功能输入框值设置问题的解决方案
核心问题分析
- NavBar组件参数误用:你把App中的
handleSearch事件处理函数当作ref传给input,这是错误的——ref用于获取DOM元素引用,输入框的输入监听应该用onChange事件。 - 无效初始请求:组件挂载时
search为空字符串,会发起?s=的无效请求,可能导致API返回错误,进而让json.Search为undefined,触发map遍历报错。 - MovieList的DOM操作与内存泄漏:直接用
document.querySelector获取DOM,且给window添加wheel事件后未清理,会导致组件卸载后事件依然存在,引发内存泄漏。
修正后的完整代码
App.jsx
import React, { useEffect, useState, useRef } from 'react'; import "./App.css"; import MovieList from './Components/MovieList'; import NavBar from './Components/NavBar'; function App() { const [data, setData] = useState([]); const [search, setSearch] = useState(''); const debounceRef = useRef(null); useEffect(() => { // 空字符串时不发起请求,同时清空列表 if (!search.trim()) { setData([]); return; } // 防抖:输入间隔300ms再请求,避免频繁调用API if (debounceRef.current) clearTimeout(debounceRef.current); debounceRef.current = setTimeout(() => { fetch(`http://www.omdbapi.com/?s=${search}&apikey=a8b01dfe`) .then(response => response.json()) .then(json => { // 处理API无结果的情况,避免报错 setData(json.Search || []); }) .catch(error => { console.error(error); setData([]); }); }, 300); // 组件卸载时清除定时器 return () => { if (debounceRef.current) clearTimeout(debounceRef.current); }; }, [search]); const handleSearch = (e) => { setSearch(e.target.value); } return ( <div> <MovieList movie={data}/> {/* 修改参数名,明确是事件处理函数 */} <NavBar onSearch={handleSearch} searchValue={search} /> </div> ); } export default App;
NavBar.jsx
import React from 'react'; function NavBar(props) { return ( <div> {/* 用onChange绑定事件,添加value实现完全受控组件 */} <input type='text' placeholder='Search...' onChange={props.onSearch} value={props.searchValue} /> </div> ); } export default NavBar;
MovieList.jsx
import React, { useEffect, useRef } from 'react'; import "./Style/MovieList.css" function MovieList(props) { // 用useRef获取组件内的DOM元素,替代全局查询 const containerRef = useRef(null); useEffect(() => { const handleWheel = (e) => { if (!containerRef.current) return; // 阻止默认滚动,避免影响页面整体滚动 e.preventDefault(); containerRef.current.scrollLeft += e.deltaY; }; const container = containerRef.current; if (container) { container.addEventListener('wheel', handleWheel); } // 组件卸载时移除事件监听,防止内存泄漏 return () => { if (container) { container.removeEventListener('wheel', handleWheel); } }; }, []); return ( <div className='movie-list-main-container' ref={containerRef}> {props.movie.map((item) => ( <div className='movies' key={item.imdbID}> {/* 处理海报为N/A的情况,避免图片加载失败 */} <img src={item.Poster !== "N/A" ? item.Poster : "https://via.placeholder.com/150"} alt={item.Title} /> </div> ))} </div> ); } export default MovieList;
关键修复点说明
- NavBar事件绑定修正:将
ref改为onChange绑定事件处理函数,同时传入searchValue实现受控组件,确保输入框值与state完全同步。 - 搜索请求优化:
- 空字符串时不发起请求并清空列表
- 添加防抖逻辑,减少无效API调用
- 处理API无结果的边界情况,避免报错
- MovieList优化:
- 用
useRef获取组件内部DOM,避免全局查询 - 将wheel事件绑定到容器元素,不影响页面其他部分
- 添加事件清理函数,防止内存泄漏
- 处理海报加载失败的情况,用占位图替代
- 使用唯一的
imdbID作为key,比index更稳定
- 用
内容的提问来源于stack exchange,提问作者Mirza Šabanović
相关产品推荐
相关产品推荐

