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

React自定义过滤hook useFilterData首次渲染返回空列表问题求助

问题根源

  1. useState初始值仅在Hook首次挂载时生效:首次调用useFilterData时,你的data大概率还未加载完成(比如是异步接口返回数据),初始值为空数组,因此filteredList被初始化为空。后续data加载完成更新后,useState不会重新读取初始值,且你原有逻辑中useEffect仅监听searchValue,不会触发重新过滤,直到修改搜索值后才会拿到最新data计算结果。
  2. 监听data触发无限循环的原因:你传入的data、keyList每次渲染都会生成新的引用(比如组件内每次渲染都重新生成数组、异步返回数据未做引用稳定处理),useEffect依赖浅对比每次都判定依赖更新,触发setState后又引发重渲染,形成死循环。
  3. 补充日志的异常也符合上述逻辑:首次log是data更新后重渲染时打印的已加载完成数据,但useState初始值已经在挂载阶段读取了当时的空数组,因此后续打印的filteredList始终为空。

解决方案

最优方案:用useMemo重构Hook(无状态同步问题,无无限循环风险)

过滤逻辑本身是输入参数的纯计算行为,无需用useState存储结果,直接用useMemo缓存计算结果即可,天然解决首次渲染不同步的问题:

import React from 'react'
import { matchSorter } from 'match-sorter'

const useFilterData = (searchValue, keyList, data) => {
  const filteredList = React.useMemo(() => {
    if (!searchValue) return data
    return matchSorter(data, searchValue, {
      keys: keyList,
    })
  }, [searchValue, keyList, data])
  return [filteredList]
}

export default useFilterData

组件侧配合稳定引用

组件内生成的columnKeys默认每次渲染都是新数组,需要用useMemo稳定引用,避免不必要的重复计算:

// data如果是异步接口返回,请存储在useState中,保证仅数据实际变化时才更新引用
const data = [{}, {}, {}] 
const columns = [{'field': 'one'}, {'field': 'two'}, {'field': 'three'}]
// 用useMemo稳定columnKeys引用,仅columns变化时才重新生成
const columnKeys = React.useMemo(() => columns.map((c) => c.field), [columns])
const [searchValue, setSearchValue] = React.useState('')
const [filteredList] = useFilterData(
    searchValue,
    columnKeys,
    data,
)

return (
  <div>
    <Paper>
      {/* 补充value属性变为受控组件,避免输入异常 */}
      <TextField onChange={(e) => setSearchValue(e.target.value)} value={searchValue} />
      <DataGrid
        rows={filteredList}
        columns={columns}
      />
    </Paper>
  </div>
)
}

内容的提问来源于stack exchange,提问作者watermelon_party

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.13 08:06:01