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

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} />
    </>
  );
};
为什么之前的方法有问题
  1. 直接在组件中调用setFilteredData:React禁止在渲染阶段直接调用setState,这会触发无限重渲染循环,因此该操作会被React忽略。
  2. 在useQuery查询函数中设置状态:违反了单一职责原则,查询函数应仅负责获取并返回数据,状态更新应由组件的副作用处理。此外,refetchInterval触发时会重复调用setFilteredData,引发不必要的组件渲染。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 15:40:07