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

如何用React Hook将多个Filter组件状态聚合为一个主状态?

问题描述

我有一个可复用的Filter组件,能根据传入的预设列表生成复选框组或单选按钮组,示例数据如下:

const genre = ["Action", "Horror", "Comedy", "Drama"];
const contenttype = ["Series", "Movies", "Documentaries"];
const dategranularity = ["All Time", "Yearly", "Monthly", "Weekly"];

组件使用方式:

<Filter data={genre} label="Genre" checkboxgroup />
<Filter data={contenttype} label="Content Type" checkboxgroup />
<Filter data={dategranularity} label="Date Granularity" defaultValue="all time" />

当前Filter组件的简化实现:

const Filter = ({ data, label, checkboxgroup, defaultValue }) => {
  const [checkedState, setCheckedState] = useState([]);
  const [radios, setRadios] = useState([]);
  const [values, setValues] = useState([]);

  const handleList = (e) => {
    const updatedValuesState = values.includes(e.target.name)
      ? values.filter((label) => label !== e.target.name)
      : [...values, e.target.name];
    setValues(updatedValuesState);
    setActive(updatedValuesState.length === data.length);
  };
};

现在的问题是:每个Filter组件单独维护自身的选中状态,比如选中Genre的Action和Horror时,只能得到values: ['action', 'horror'];切换到Content Type选中Series时,状态被重置,只能得到values: ['series']。我需要实现跨组件的状态聚合,最终输出合并后的选中值,比如values: ['action', 'horror', 'series'],其中单选按钮组仅保留最后选中的一个值,复选框组可保留多个选中值。

解决方案

核心思路是状态提升:把所有Filter的选中状态统一放在父组件中管理,Filter组件只负责渲染和触发状态更新,不维护自身状态。

1. 父组件统一管理聚合状态

父组件中定义状态filterSelections,用对象结构存储每个Filter的选中值,键为Filter的label,值对应复选框的选中数组或单选的单个值:

const [filterSelections, setFilterSelections] = useState({
  Genre: [],
  "Content Type": [],
  "Date Granularity": "all time" // 匹配单选的默认值
});

2. 给Filter组件传递状态和更新函数

在父组件中使用Filter时,传入对应分组的选中值和状态更新回调:

<Filter 
  data={genre} 
  label="Genre" 
  checkboxgroup 
  selectedValues={filterSelections["Genre"]}
  onSelectionChange={(newValues) => {
    setFilterSelections(prev => ({...prev, "Genre": newValues}));
  }}
/>

<Filter 
  data={contenttype} 
  label="Content Type" 
  checkboxgroup 
  selectedValues={filterSelections["Content Type"]}
  onSelectionChange={(newValues) => {
    setFilterSelections(prev => ({...prev, "Content Type": newValues}));
  }}
/>

<Filter 
  data={dategranularity} 
  label="Date Granularity" 
  selectedValues={filterSelections["Date Granularity"]}
  onSelectionChange={(newValue) => {
    setFilterSelections(prev => ({...prev, "Date Granularity": newValue}));
  }}
/>

3. 改造Filter组件的逻辑

移除组件内部的状态,基于父组件传入的selectedValues渲染选项,选中变化时调用父组件的更新函数:

const Filter = ({ data, label, checkboxgroup, selectedValues, onSelectionChange }) => {
  const handleSelection = (e) => {
    const value = e.target.name.toLowerCase();
    let newSelection;
    
    if (checkboxgroup) {
      // 复选框逻辑:添加/移除选中项
      newSelection = selectedValues.includes(value)
        ? selectedValues.filter(item => item !== value)
        : [...selectedValues, value];
    } else {
      // 单选逻辑:直接替换为当前选中值
      newSelection = value;
    }
    
    onSelectionChange(newSelection);
  };

  return (
    <div className="filter-group">
      <h3>{label}</h3>
      {data.map(item => {
        const itemValue = item.toLowerCase();
        const isChecked = checkboxgroup 
          ? selectedValues.includes(itemValue)
          : selectedValues === itemValue;
        
        return (
          <div key={item}>
            <input
              type={checkboxgroup ? "checkbox" : "radio"}
              name={itemValue}
              checked={isChecked}
              onChange={handleSelection}
            />
            <label>{item}</label>
          </div>
        );
      })}
    </div>
  );
};

4. 获取聚合后的所有选中值

在父组件中通过计算属性提取所有选中值:

const aggregatedValues = Object.values(filterSelections).flat();
// 示例输出:['action', 'horror', 'series', 'all time']
// 若需排除单选默认值,可根据需求添加过滤逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 20:21:11