React Hooks实现带Debounce的搜索框:技术问题咨询
React自动完成组件问题解答
原代码
import React, { useEffect, useState } from 'react' import axios from 'axios' function AutoCompleteInput() { const[data,setData] = useState([]) const [filtereddata,setfilteredData]=useState([]) useEffect(()=>{ const Timer = setTimeout(()=>{ axios.get('https://jsonplaceholder.typicode.com/users') .then((res)=>{ //console.log(res.data[0]) setData(res.data) setfilteredData(res.data) }) .catch((err)=>console.log("some error")) },2000) return()=>clearTimeout(Timer) },[data]) const handleChange=(searchvalue)=>{ // console.log(value) const filteritems= filtereddata.filter(item=>item.name.toLowerCase().includes(searchvalue)) //console.log(filteritems) setData(filteritems) } return ( <div> <input type="text" placeholder="search here..." onChange={(e)=>handleChange(e.target.value)}/> <div> <table> <thead> <tr> <th>name</th> <th>username</th> <th>email</th> <th>phone</th> </tr> </thead> <tbody> {data.map((d,i)=>{ return ( <tr key={i}> <td>{i+1}</td> <td>{d.name}</td> <td>{d.username}</td> <td>{d.email}</td> <td>{d.phone}</td> </tr> ) })} </tbody> </table> </div> </div> ) } export default AutoCompleteInput
问题解答
1. useEffect依赖数组配置问题
你把[data]作为依赖数组,会导致每次data变化(比如搜索过滤后),useEffect重新执行,再次请求API并将data和filtereddata重置为完整用户列表,这就是搜索后又恢复全量数据的原因。
正确配置是依赖数组设为空数组[],这样useEffect只会在组件首次挂载时执行一次,初始化全量数据,后续不会因data变化重复触发:
useEffect(()=>{ const Timer = setTimeout(()=>{ axios.get('https://jsonplaceholder.typicode.com/users') .then((res)=>{ setData(res.data) setfilteredData(res.data) }) .catch((err)=>console.log("some error")) },2000) return()=>clearTimeout(Timer) },[]) // 改为空数组
2. 搜索防抖与数据展示问题
你目前的2秒定时器是加在初始化API请求上,不是搜索的防抖逻辑,导致两个问题:
- 初始化数据要等2秒才加载,这段时间输入搜索内容时,
filtereddata还是空数组,过滤结果自然为空 - 没有对搜索输入做防抖,每次输入都会立刻触发过滤(若后续改成后端搜索,会产生频繁请求)
解决步骤:
调整初始化请求的延迟:如果不需要刻意延迟加载,直接去掉setTimeout,让数据尽快加载:
useEffect(()=>{ axios.get('https://jsonplaceholder.typicode.com/users') .then((res)=>{ setData(res.data) setfilteredData(res.data) }) .catch((err)=>console.log("some error")) },[])给搜索输入添加防抖:
用useCallback结合定时器实现防抖,避免输入过程中频繁触发过滤:import React, { useEffect, useState, useCallback } from 'react' import axios from 'axios' function AutoCompleteInput() { const[data,setData] = useState([]) const [filtereddata,setfilteredData]=useState([]) const [searchValue, setSearchValue] = useState('') // 新增状态存储搜索值 // 防抖处理的过滤函数 const debouncedFilter = useCallback(() => { const filterItems = filtereddata.filter(item => item.name.toLowerCase().includes(searchValue.toLowerCase()) ) setData(filterItems) }, [searchValue, filtereddata]) useEffect(() => { const timer = setTimeout(debouncedFilter, 300) // 300ms防抖延迟 return () => clearTimeout(timer) }, [debouncedFilter]) const handleChange=(value)=>{ setSearchValue(value) } // 初始化请求部分改为空数组依赖 useEffect(()=>{ axios.get('https://jsonplaceholder.typicode.com/users') .then((res)=>{ setData(res.data) setfilteredData(res.data) }) .catch((err)=>console.log("some error")) },[]) // ...返回部分代码不变 } export default AutoCompleteInput
另外注意:你代码里表格thead的列数(4列)和tbody的列数(5列)不匹配,建议调整thead加上序号列,或者去掉tbody的序号列,避免布局错乱。
内容的提问来源于stack exchange,提问作者pooja thakur
相关产品推荐
相关产品推荐

