如何用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
相关产品推荐
相关产品推荐

