react-query首次加载时数据过滤失效问题求助
问题分析
核心问题是filteredData的初始值仅在组件首次渲染时被设置为data(此时data为undefined),当react-query完成数据加载、data更新后,没有机制同步更新filteredData,导致表格始终使用初始的undefined值,直到搜索操作触发setFilteredData才恢复正常。
你尝试直接在组件渲染流程中调用setFilteredData(data)会触发无限重渲染(设置状态引发组件重渲染,重渲染又调用setState,形成循环),因此React会阻止该操作,导致无效。而在useQuery的查询函数里设置状态虽然能生效,但会破坏react-query的职责分离(查询函数应仅负责获取数据,不处理状态更新),还可能在refetchInterval触发时重复设置状态,引发不必要的渲染。
解决方案
推荐两种可靠的实现方式:
方式一:用useEffect同步data到filteredData
通过监听data和搜索文本的变化,自动同步并更新过滤后的数据:
import { useState, useEffect } from 'react'; import { useQuery } from '@tanstack/react-query'; import DataTable from 'react-data-table-component'; const YourComponent = () => { const { data, isLoading } = useQuery(["whatever"], () => getDataFromBackend(), { refetchInterval: 10000 }); const [searchText, setSearchText] = useState(''); const [filteredData, setFilteredData] = useState([]); // 监听data和searchText变化,自动更新过滤结果 useEffect(() => { if (!data) return; if (!searchText) { setFilteredData(data); return; } // 替换为你的实际过滤逻辑 const result = data.filter(item => item.name.toLowerCase().includes(searchText.toLowerCase()) || item.id.includes(searchText) ); setFilteredData(result); }, [data, searchText]); const onSearch = (text) => { setSearchText(text); }; if (isLoading) { return <div>Loading..</div>; } return ( <> <input type="text" placeholder="搜索..." value={searchText} onChange={(e) => onSearch(e.target.value)} /> <DataTable data={filteredData} /> </> ); };
方式二:无需额外状态,渲染时直接计算(推荐)
如果过滤逻辑不复杂,可以直接在渲染阶段基于data和searchText计算结果,用useMemo缓存避免重复计算:
import { useState, useMemo } from 'react'; import { useQuery } from '@tanstack/react-query'; import DataTable from 'react-data-table-component'; const YourComponent = () => { const { data, isLoading } = useQuery(["whatever"], () => getDataFromBackend(), { refetchInterval: 10000 }); const [searchText, setSearchText] = useState(''); // 用useMemo缓存过滤结果,仅在data或searchText变化时重新计算 const filteredData = useMemo(() => { if (!data) return []; if (!searchText) { return data; } // 替换为你的实际过滤逻辑 return data.filter(item => item.name.toLowerCase().includes(searchText.toLowerCase()) ); }, [data, searchText]); const onSearch = (text) => { setSearchText(text); }; if (isLoading) { return <div>Loading..</div>; } return ( <> <input type="text" placeholder="搜索..." value={searchText} onChange={(e) => onSearch(e.target.value)} /> <DataTable data={filteredData} /> </> ); };
为什么之前的方法有问题
- 直接在组件中调用setFilteredData:React禁止在渲染阶段直接调用setState,这会触发无限重渲染循环,因此该操作会被React忽略。
- 在useQuery查询函数中设置状态:违反了单一职责原则,查询函数应仅负责获取并返回数据,状态更新应由组件的副作用处理。此外,
refetchInterval触发时会重复调用setFilteredData,引发不必要的组件渲染。
内容的提问来源于stack exchange,提问作者LNI
相关产品推荐
相关产品推荐

