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

React输入框过滤API获取数据异常问题排查与修复

问题:输入关键词后API数据过滤未达预期

我设置了一个输入框,期望根据标题过滤从API获取的数据,但输入正确关键词后,过滤结果并未达到预期效果。

代码示例

"use client";
import React, { useEffect, useState } from 'react';

const FetchWithFilter = () => {
  const [data, setData] = useState([]);
  const [filter, setFilter] = useState("");
  const [filteredData, setFilteredData] = useState([]);

  async function fetchData() {
    try {
      const response = await fetch('https://jsonplaceholder.typicode.com/posts');
      const data = await response.json();
      setData(data);
      setFilteredData(data); // initialize filteredData
    } catch (error) {
      console.error("Error fetching data:", error);
    }
  }

  const handleFilterChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const value = event.target.value;
    setFilter(value);
    const filtered = data.filter(item =>
      item.title.toLowerCase().includes(value.toLowerCase())
    );
    setFilteredData(filtered);
  };

  useEffect(() => {
    fetchData();
  }, []);

  return (
    <div>
      <h1 className="text-2xl font-bold">Fetch Data</h1>
      <input
        type="text"
        placeholder="Filter by title..."
        value={filter}
        onChange={handleFilterChange}
        className="border border-gray-300 rounded px-2 py-1 mb-4"
      />
      <button onClick={fetchData} className="bg-[red] rounded-2xl px-4">
        Fetch Data
      </button>
      <ul className="space-y-2">
        {filteredData.map(item => (
          <li className="border-b pb-2" key={item.id}>
            <strong>{item.title}</strong>
            <p>{item.body}</p>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default FetchWithFilter;

问题原因

  • 状态不同步:每次调用fetchData时,会直接将filteredData重置为全部数据,忽略当前的filter值。比如输入关键词过滤出结果后,点击Fetch Data按钮,过滤结果会被重置为所有数据。
  • 闭包捕获旧状态:数据加载完成前输入关键词,过滤会基于空数组返回空结果;数据加载完成后,filteredData被设为全部数据,但此时filter仍保留输入值,却未重新执行过滤,导致显示全部数据而非预期结果。
  • 冗余状态维护:filteredData属于衍生状态,可通过data和filter实时计算,单独维护容易出现状态不同步问题。

修复方法

方案一:用useEffect监听状态变化更新过滤结果

将过滤逻辑移到useEffect中,只要data或filter变化就重新计算:

"use client";
import React, { useEffect, useState } from 'react';

const FetchWithFilter = () => {
  const [data, setData] = useState([]);
  const [filter, setFilter] = useState("");
  const [filteredData, setFilteredData] = useState([]);

  async function fetchData() {
    try {
      const response = await fetch('https://jsonplaceholder.typicode.com/posts');
      const fetchedData = await response.json();
      setData(fetchedData);
    } catch (error) {
      console.error("Error fetching data:", error);
    }
  }

  // 监听data和filter变化,重新计算过滤结果
  useEffect(() => {
    const filtered = data.filter(item =>
      item.title.toLowerCase().includes(filter.toLowerCase())
    );
    setFilteredData(filtered);
  }, [data, filter]);

  const handleFilterChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setFilter(event.target.value);
  };

  useEffect(() => {
    fetchData();
  }, []);

  return (
    <div>
      <h1 className="text-2xl font-bold">Fetch Data</h1>
      <input
        type="text"
        placeholder="Filter by title..."
        value={filter}
        onChange={handleFilterChange}
        className="border border-gray-300 rounded px-2 py-1 mb-4"
      />
      <button onClick={fetchData} className="bg-[red] rounded-2xl px-4">
        Fetch Data
      </button>
      <ul className="space-y-2">
        {filteredData.map(item => (
          <li className="border-b pb-2" key={item.id}>
            <strong>{item.title}</strong>
            <p>{item.body}</p>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default FetchWithFilter;

方案二:移除冗余状态,渲染时实时计算(推荐)

直接在渲染阶段计算过滤结果,避免维护额外状态:

"use client";
import React, { useEffect, useState } from 'react';

const FetchWithFilter = () => {
  const [data, setData] = useState([]);
  const [filter, setFilter] = useState("");

  async function fetchData() {
    try {
      const response = await fetch('https://jsonplaceholder.typicode.com/posts');
      const fetchedData = await response.json();
      setData(fetchedData);
    } catch (error) {
      console.error("Error fetching data:", error);
    }
  }

  const handleFilterChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setFilter(event.target.value);
  };

  useEffect(() => {
    fetchData();
  }, []);

  // 实时计算过滤结果
  const filteredData = data.filter(item =>
    item.title.toLowerCase().includes(filter.toLowerCase())
  );

  return (
    <div>
      <h1 className="text-2xl font-bold">Fetch Data</h1>
      <input
        type="text"
        placeholder="Filter by title..."
        value={filter}
        onChange={handleFilterChange}
        className="border border-gray-300 rounded px-2 py-1 mb-4"
      />
      <button onClick={fetchData} className="bg-[red] rounded-2xl px-4">
        Fetch Data
      </button>
      <ul className="space-y-2">
        {filteredData.map(item => (
          <li className="border-b pb-2" key={item.id}>
            <strong>{item.title}</strong>
            <p>{item.body}</p>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default FetchWithFilter;

说明

方案二更简洁可靠,彻底避免了状态不同步的问题。当data或filter变化时,组件会自动重新渲染并计算最新的过滤结果,确保显示内容始终符合预期。

内容的提问来源于stack exchange,提问作者FAIZAN AHMED TANOLI

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 03:24:56