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

React中点击分类按钮后UI组件未更新的问题排查求助

电商分类筛选功能失效:点击按钮后UI未同步更新

我正在构建一个电商项目,想实现点击分类按钮按类别筛选商品并在UI展示的功能,但点击按钮后,控制台显示筛选后的数组已经更新,可页面上始终显示全部商品列表。附上我的代码和问题截图:

import React, { useState, useEffect } from "react";
import "./ItemComponent.css";

function ItemsComponent() {
  const [items, setItems] = useState([]);
  const [search, setSearch] = useState("");
  const [filterItems, setFilterItems] = useState(items);

  // Fetching Data
  useEffect(() => {
    const fetchedData = async () => {
      try {
        const response = await fetch(`https://fakestoreapi.com/products`);
        const data = await response.json();
        console.log("Data", data);
        setItems(data);
      } catch (error) {
        console.log(error);
      }
    };
    fetchedData();
  }, []);

  const handleSubmit = (e) => {
    e.preventDefault();
  };

  const filterProduct = (cat) => {
    const updatedList = items.filter((item) => item.category === cat);
    console.log("cat", cat);
    console.log("updated", updatedList);
    setFilterItems(updatedList);
  };

  return (
    <>
      <header>
        <div className="overlay">
          <h2>Welcome To E-Commerce Shop</h2>
        </div>
        <div className="search">
          <form onSubmit={handleSubmit}>
            <input
              type="text"
              placeholder="Search..."
              onChange={(e) => setSearch(e.target.value)}
            />
            <button className="btn-light btn-search">Search</button>
          </form>
        </div>
        <div className="categories">
          <button
            className="btn-dark category"
            onClick={() => setFilterItems(items)}
          >
            All
          </button>
          <button
            className="btn-dark category"
            onClick={() => filterProduct("men's clothing")}
          >
            Men's Clothing
          </button>
          <button
            className="btn-dark category"
            onClick={() => filterProduct("women's clothing")}
          >
            Women's Closing
          </button>
          <button
            className="btn-dark category"
            onClick={() => filterProduct("jewelery")}
          >
            Jewelry
          </button>
          <button
            className="btn-dark category"
            onClick={() => filterProduct("electronics")}
          >
            Electronics
          </button>
        </div>
      </header>
      <div className="display-grid">
        {Array.from(items)
          .filter((value) => {
            if (search === "") {
              return value;
            } else if (
              value.title.toLowerCase().includes(search.toLowerCase())
            ) {
              return value;
            }
          })
          .map((item) => (
            <div key={item.id}>
              <div className="card">
                <p className="title">{item.title}</p>
                <img src={item.image} />
                {/* <p className="description">{item.description}</p> */}
                <p className="price">£ {item.price}</p>
                <button className="btn-dark btn-buy">
                  <a href="#" className="btn-link">
                    Buy Now
                  </a>
                </button>
              </div>
            </div>
          ))}
      </div>
    </>
  );
}

export default ItemsComponent;

问题截图


问题根源

核心问题是UI渲染时始终使用原始的items数组,而非更新后的filterItems数组。虽然点击按钮后filterItems状态已正确更新,但页面渲染逻辑完全没用到这个状态,所以UI不会同步变化。

另外还有两个隐性问题:

  1. filterItems初始化时依赖空数组items,数据获取后未同步更新filterItems,导致初始状态下filterItems为空。
  2. 搜索功能仅基于items过滤,未结合分类后的filterItems,会导致分类后搜索失效。

修复方案

  1. 渲染时改用filterItems数组:将商品展示逻辑从Array.from(items)替换为Array.from(filterItems)。
  2. 同步初始filterItems状态:添加useEffect监听items变化,数据获取完成后自动将filterItems设为全部商品。
  3. 整合搜索与分类逻辑:搜索过滤基于filterItems,确保分类后搜索依然有效。

修复后的完整代码

import React, { useState, useEffect } from "react";
import "./ItemComponent.css";

function ItemsComponent() {
  const [items, setItems] = useState([]);
  const [search, setSearch] = useState("");
  const [filterItems, setFilterItems] = useState([]);

  // Fetching Data
  useEffect(() => {
    const fetchedData = async () => {
      try {
        const response = await fetch(`https://fakestoreapi.com/products`);
        const data = await response.json();
        console.log("Data", data);
        setItems(data);
        setFilterItems(data); // 数据获取后同步设置filterItems为全部商品
      } catch (error) {
        console.log(error);
      }
    };
    fetchedData();
  }, []);

  const handleSubmit = (e) => {
    e.preventDefault();
  };

  const filterProduct = (cat) => {
    const updatedList = items.filter((item) => item.category === cat);
    console.log("cat", cat);
    console.log("updated", updatedList);
    setFilterItems(updatedList);
  };

  return (
    <>
      <header>
        <div className="overlay">
          <h2>Welcome To E-Commerce Shop</h2>
        </div>
        <div className="search">
          <form onSubmit={handleSubmit}>
            <input
              type="text"
              placeholder="Search..."
              onChange={(e) => setSearch(e.target.value)}
            />
            <button className="btn-light btn-search">Search</button>
          </form>
        </div>
        <div className="categories">
          <button
            className="btn-dark category"
            onClick={() => setFilterItems(items)}
          >
            All
          </button>
          <button
            className="btn-dark category"
            onClick={() => filterProduct("men's clothing")}
          >
            Men's Clothing
          </button>
          <button
            className="btn-dark category"
            onClick={() => filterProduct("women's clothing")}
          >
            Women's Clothing {/* 修复拼写错误:Closing -> Clothing */}
          </button>
          <button
            className="btn-dark category"
            onClick={() => filterProduct("jewelery")}
          >
            Jewelry
          </button>
          <button
            className="btn-dark category"
            onClick={() => filterProduct("electronics")}
          >
            Electronics
          </button>
        </div>
      </header>
      <div className="display-grid">
        {Array.from(filterItems) // 改用filterItems渲染
          .filter((value) => {
            if (search === "") {
              return value;
            } else if (
              value.title.toLowerCase().includes(search.toLowerCase())
            ) {
              return value;
            }
            return false; // 补全默认返回值
          })
          .map((item) => (
            <div key={item.id}>
              <div className="card">
                <p className="title">{item.title}</p>
                <img src={item.image} alt={item.title} /> {/* 添加alt属性优化可访问性 */}
                <p className="price">£ {item.price}</p>
                <button className="btn-dark btn-buy">
                  <a href="#" className="btn-link">
                    Buy Now
                  </a>
                </button>
              </div>
            </div>
          ))}
      </div>
    </>
  );
}

export default ItemsComponent;

额外修正说明

  • 修复了按钮文本拼写错误:Women's Closing → Women's Clothing,避免分类匹配失败。
  • 给图片添加alt属性,符合网页可访问性规范。
  • 补全搜索过滤函数的默认返回值,避免逻辑漏洞。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 06:10:58