You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

React.js产品按品牌二次筛选失效问题求助附代码

问题分析与解决方案

你遇到的问题非常典型——第一次筛选后原始产品数据被覆盖了!当你调用setProducts(products.filter(...))时,直接把筛选后的子集替换了原有的products状态,第二次切换品牌时,只能基于这个子集再过滤,自然找不到其他品牌的产品了。

修复核心思路

保留一份原始产品数据的副本,每次筛选都基于原始数据来处理,而不是修改原状态,这样就能保证每次筛选的数据源都是完整的。

修改后的完整代码

import React, { useEffect, useState } from 'react'
import Loader from './../Loader/Loader'
import ProductItem from './ProductItem'

function Catalog() {
  // 新增:专门存储从API获取的完整原始产品列表
  const [originalProducts, setOriginalProducts] = useState([])
  const [products, setProducts] = useState([])
  const [brands, setBrands] = useState([])
  const [brand, setBrand] = useState('')

  useEffect(() => {
    const proxyUrl = 'https://cors-anywhere.herokuapp.com/'
    const url = 'https://avtodoka-msk.ru/aimylogic-mission.json'
    fetch(proxyUrl + url)
      .then(response => response.json())
      .then(fetchedProducts => {
        // 同时初始化原始数据和展示用数据
        setOriginalProducts(fetchedProducts)
        setProducts(fetchedProducts)
        
        // 优化:用flatMap更简洁地收集所有品牌(替代map+push)
        const allBrands = fetchedProducts.flatMap(product => product.brend)
        setBrands([...new Set(allBrands)])
      })
  }, [])

  function toggleBrand(e) {
    const selectedBrand = e.target.value
    setBrand(selectedBrand)
    
    // 基于原始数据做筛选
    if (!selectedBrand) {
      // 选择"全部品牌"时重置为完整数据
      setProducts(originalProducts)
      return
    }
    
    setProducts(
      originalProducts.filter(product => {
        // 兼容处理:确保product.brend是数组(避免潜在报错)
        return Array.isArray(product.brend) && product.brend.includes(selectedBrand)
      })
    )
  }

  return (
    <div className="container pt-5">
      {brands.length ? (
        <div className="row">
          <div className="col-3">
            <select value={brand} onChange={toggleBrand}>
              <option value={''}>Выбрать бренд</option>
              {brands.map((brend, index) => (
                <option value={brend} key={index}>{brend}</option>
              ))}
            </select>
          </div>
        </div>
      ) : null}
      {products.length ? (
        <div className="row">
          {products.map(product => (
            <ProductItem key={product.id} product={product} />
          ))}
        </div>
      ) : <Loader />}
    </div>
  )
}

export default Catalog

额外优化建议

如果想进一步提升性能,可以用useMemo缓存筛选结果,避免每次组件渲染都重复执行过滤逻辑:

const filteredProducts = React.useMemo(() => {
  if (!brand) return originalProducts
  return originalProducts.filter(product => 
    Array.isArray(product.brend) && product.brend.includes(brand)
  )
}, [originalProducts, brand])

之后把渲染部分的products换成filteredProducts,还可以直接去掉products状态,让逻辑更简洁。

内容的提问来源于stack exchange,提问作者Як Цидрак

火山引擎 最新活动