You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
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;

关键修复点说明

  1. NavBar事件绑定修正:将ref改为onChange绑定事件处理函数,同时传入searchValue实现受控组件,确保输入框值与state完全同步。
  2. 搜索请求优化:
    • 空字符串时不发起请求并清空列表
    • 添加防抖逻辑,减少无效API调用
    • 处理API无结果的边界情况,避免报错
  3. MovieList优化:
    • 用useRef获取组件内部DOM,避免全局查询
    • 将wheel事件绑定到容器元素,不影响页面其他部分
    • 添加事件清理函数,防止内存泄漏
    • 处理海报加载失败的情况,用占位图替代
    • 使用唯一的imdbID作为key,比index更稳定

内容的提问来源于stack exchange,提问作者Mirza Šabanović

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 20:23:12