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

React基于选中分类的食谱列表过滤功能实现问询

食谱多选分类过滤问题解决方案

问题场景

你在React项目中实现食谱分类过滤:通过recipesCategories循环渲染RecipeCategory组件作为分类按钮,初始所有分类均为选中状态,需求是选中的分类需要将所有标签匹配该分类的食谱加入展示列表,但当前子组件的ChangeRecipeList函数无法正确实现多选逻辑。

你的原始代码:

const recipes = [
  { name: 'Chicken-Curry-with-White-Rice', time: '35', tags: ['Indian'] },
  { name: 'Herby-Fish-Rolls', time: '35', tags: ['SeaFood'] },
  { name: 'Chicken-Shawarma-Tacos', time: '15', tags: ['Chicken', 'Quick & Easy'] },
  { name: 'Chicken-Zurbian', time: '55', tags: ['Chicken'] },
  { name: 'Shrimp-Scampi', time: '10', tags: ['SeaFood', 'Quick & Easy'] },
  { name: 'Baked-Fish-Fillet-in-Parchment-Paper', time: '40', tags: ['SeaFood'] },
  { name: 'Teriyaki-Chicken-with-Broccoli', time: '25', tags: ['Asian', 'Chicken'] },
  { name: 'Thai-Style-Chicken', time: '30', tags: ['Chicken'] },
  { name: 'Chicken-Shawarma-Salad', time: '10', tags: ['Chicken'] },
  { name: 'Bulgur-Salad-with-Grilled-Chicken', time: '25', tags: ['Chicken'] },
];

const recipesCategories = ['Asian', 'Indian', 'SeaFood', 'Quick & Easy', 'Chicken'];

const [filteredRecipes, setFilteredRecipes] = useState(recipes);

// 渲染分类按钮
{recipesCategories.map((recipe) => {
  return (
    <RecipeCategory recipeCategory={recipeCategory} filteredRecipes={filteredRecipes} setFilteredRecipes={setFilteredRecipes} />
  )
})}

// 渲染过滤后的食谱
{filteredRecipes.map((recipe) => (
  <>
    <RecipeSlide recipe={recipe} />
  </>
))}

当前子组件的错误逻辑:

const ChangeRecipeList = () => {
    let list = recipes;
    let newFilteredList = [];

    console.log('Recipe Catgory:', recipeCategory)

    newFilteredList = list.filter((Recipe) => selected && Recipe.tags.includes(recipeCategory) )
    console.log('State List:', filteredRecipes)

    console.log('Updated List:', newFilteredList)
    setFilteredRecipes(newFilteredList)
}

当前代码的问题

  • 每个RecipeCategory组件单独维护选中状态,父组件没有统一管理所有选中分类,导致过滤逻辑只能基于单个分类,无法合并多个选中分类的结果
  • ChangeRecipeList每次只处理当前分类,直接覆盖之前的过滤结果,无法实现"多选分类时展示所有匹配任意选中分类的食谱"的需求

正确实现方案

步骤1:父组件统一管理选中状态

将选中状态从子组件移到父组件,用数组维护所有选中的分类,同时通过useEffect监听选中状态变化,自动触发过滤逻辑:

import { useState, useEffect } from 'react';

const recipes = [
  // 你的食谱数据,保持不变
];

const recipesCategories = ['Asian', 'Indian', 'SeaFood', 'Quick & Easy', 'Chicken'];

export default function RecipeApp() {
  // 初始全选所有分类
  const [selectedCategories, setSelectedCategories] = useState(recipesCategories);
  const [filteredRecipes, setFilteredRecipes] = useState(recipes);

  // 切换分类选中状态的回调
  const toggleCategory = (category) => {
    setSelectedCategories(prev => {
      if (prev.includes(category)) {
        // 已选中则移除
        return prev.filter(c => c !== category);
      } else {
        // 未选中则添加
        return [...prev, category];
      }
    });
  };

  // 选中分类变化时重新过滤食谱
  useEffect(() => {
    // 若无选中分类,展示所有食谱(可根据需求调整)
    if (selectedCategories.length === 0) {
      setFilteredRecipes(recipes);
      return;
    }
    // 筛选出标签匹配任意一个选中分类的食谱
    const filtered = recipes.filter(recipe => 
      recipe.tags.some(tag => selectedCategories.includes(tag))
    );
    setFilteredRecipes(filtered);
  }, [selectedCategories]);

  return (
    <div>
      <div className="category-buttons">
        {recipesCategories.map(category => (
          <RecipeCategory
            key={category}
            category={category}
            isSelected={selectedCategories.includes(category)}
            onToggle={() => toggleCategory(category)}
          />
        ))}
      </div>
      <div className="recipe-slides">
        {filteredRecipes.map(recipe => (
          <RecipeSlide key={recipe.name} recipe={recipe} />
        ))}
      </div>
    </div>
  );
}

步骤2:简化RecipeCategory子组件

子组件不再维护状态,仅负责渲染按钮和触发父组件的回调:

export default function RecipeCategory({ category, isSelected, onToggle }) {
  return (
    <button
      onClick={onToggle}
      className={`category-btn ${isSelected ? 'active' : ''}`}
    >
      {category}
    </button>
  );
}

核心逻辑说明

  • 父组件通过selectedCategories数组统一管理所有选中的分类,确保状态一致性
  • 利用useEffect监听选中状态变化,自动执行过滤:recipe.tags.some()判断食谱是否包含任意一个选中的分类标签
  • 子组件专注UI渲染,状态完全由父组件控制,避免了多组件状态不同步的问题
  • 初始状态设置为全选所有分类,满足需求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 08:12:45