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

React中useEffect过滤数组的错误用法及修复方法

解决React筛选后无法恢复全部卡片的问题

嘿,这个问题我之前踩过坑!核心原因很明确——你把原始的数据源直接存在了cards状态里,每次筛选都会覆盖这个状态,导致原始数据丢失,自然没法回到显示全部卡片的状态啦。

问题出在哪?

看你的代码,useEffect每次searchField变化时,会用当前的cards状态去筛选:

const filteredCards = cards.filter(...)
setCards(filteredCards);

第一次筛选后,cards已经变成了过滤后的小数据集。当你清空搜索框时,是用这个小数据集去筛选包含空字符串的结果,结果当然还是这个小数据集,没法恢复到最初的全部数据。

修复方案:保留原始数据源

我们需要把原始数据和过滤后的结果分开,永远基于原始数据做筛选操作,而不是修改原始数据的状态。这里有几种实现方式:

方式1:直接在渲染时计算过滤结果(最简洁)

最简单的方式是去掉useEffect,直接在组件渲染时基于原始data计算过滤结果,逻辑更清晰:

import { data } from './data';
import { useState } from 'react';

const SearchBox = ({ onSearchChange }) => {
  return (
    <div>
      <input type='search' placeholder='search' onChange={(e) => {
        onSearchChange(e.target.value);
      }} />
    </div>
  );
};

function App() {
  const [searchField, setSearchField] = useState('');
  
  // 每次渲染时基于原始data计算过滤结果
  const filteredCards = data.filter((card) => {
    return card.name.toLowerCase().includes(searchField.toLowerCase());
  });

  return (
    <div>
      <SearchBox onSearchChange={setSearchField} />
      <CardList cards={filteredCards} />
    </div>
  );
}

方式2:用useMemo优化性能(适用于大数据量)

如果你的data很大,每次渲染都重新过滤可能影响性能,可以用useMemo缓存过滤结果,只有当searchField或data变化时才重新计算:

import { data } from './data';
import { useState, useMemo } from 'react';

const SearchBox = ({ onSearchChange }) => {
  return (
    <div>
      <input type='search' placeholder='search' onChange={(e) => {
        onSearchChange(e.target.value);
      }} />
    </div>
  );
};

function App() {
  const [searchField, setSearchField] = useState('');
  
  // 缓存过滤结果,避免不必要的重复计算
  const filteredCards = useMemo(() => {
    return data.filter((card) => {
      return card.name.toLowerCase().includes(searchField.toLowerCase());
    });
  }, [searchField, data]); // 依赖项:只有这两个值变了才重新计算

  return (
    <div>
      <SearchBox onSearchChange={setSearchField} />
      <CardList cards={filteredCards} />
    </div>
  );
}

方式3:适配动态获取的原始数据(比如接口请求)

如果你的data不是静态导入的,而是从接口动态获取的,可以把原始数据单独存在状态里,再基于它做筛选:

import { useState, useEffect, useMemo } from 'react';

function App() {
  const [originalCards, setOriginalCards] = useState([]);
  const [searchField, setSearchField] = useState('');

  // 模拟从接口获取原始数据
  useEffect(() => {
    fetch('/api/cards')
      .then(res => res.json())
      .then(data => setOriginalCards(data));
  }, []);
  
  const filteredCards = useMemo(() => {
    return originalCards.filter((card) => {
      return card.name.toLowerCase().includes(searchField.toLowerCase());
    });
  }, [searchField, originalCards]);

  return (
    <div>
      <SearchBox onSearchChange={setSearchField} />
      <CardList cards={filteredCards} />
    </div>
  );
}

核心总结

不管用哪种方式,关键都是不要覆盖原始数据源,所有筛选操作都要基于原始数据来执行。这样当你清空搜索框时,过滤逻辑会基于全部原始数据重新计算,自然就能回到显示全部卡片的状态啦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:23:39