如何基于数组创建多个React useState或用单状态对象管理组件状态?
解决方案
1. 将多个状态合并为单个对象
无需单独声明多个useState,可以基于options数组自动生成一个包含所有筛选器的状态对象,维护更便捷:
// 根据options自动生成初始筛选状态,每个选项的name作为键,初始值为空数组 const [allFilters, setAllFilters] = React.useState( options.reduce((acc, option) => { acc[option.name] = []; return acc; }, {}) );
2. 仅更新单个筛选器属性
编写专门的更新函数,通过函数式更新语法修改目标属性,同时保留其他状态不变:
// 接收筛选器key和新值,精准更新对应属性 const updateFilter = (filterKey, newValue) => { setAllFilters(prevState => ({ ...prevState, // 展开原有状态,保留其他属性 [filterKey]: newValue // 替换目标属性的新值 })); };
3. 基于数组循环创建customFilter
直接遍历options数组,为每个选项渲染customFilter组件,传入对应的状态和绑定好的更新函数:
// 在return中循环渲染所有筛选器 return ( <> {options.map(option => ( customFilter( option, allFilters[option.name], (newValue) => updateFilter(option.name, newValue) ) ))} </> );
完整修改后的代码
import * as React from 'react'; import TransferList from './TransferList'; import Accordion from '@mui/material/Accordion'; import AccordionSummary from '@mui/material/AccordionSummary'; import AccordionDetails from '@mui/material/AccordionDetails'; import Typography from '@mui/material/Typography'; import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward'; export default function CustomFormatBox() { const options = [ { name: 'sample_type_key', label: 'Sample Type', defaultOperator: 'in', valueEditorType: 'multiselect', values: [ { name: '0', label: 'OPTICAL_BLANK_0' }, { name: '1', label: 'OPTICAL_BLANK_1' }, ], }, { name: 'cuvette_number', label: 'Cuvette Number', defaultOperator: 'in', valueEditorType: 'multiselect', values: [ { name: '0', label: '0' }, { name: '1', label: '1' }, { name: '2', label: '2' }, ], }, { name: 'wavelength_key', label: 'Wavelength', values: [ { name: '0', label: '340nm' }, { name: '8', label: '850nm' }, ], }, ]; // 自动生成初始筛选状态 const [allFilters, setAllFilters] = React.useState( options.reduce((acc, option) => { acc[option.name] = []; return acc; }, {}) ); // 单个筛选器更新函数 const updateFilter = (filterKey, newValue) => { setAllFilters(prevState => ({ ...prevState, [filterKey]: newValue })); }; const customFilter = (option, right, setRight) => ( <Accordion key={option.name}> {/* 添加唯一key避免React警告 */} <AccordionSummary expandIcon={<ArrowDownwardIcon />} aria-controls={`panel-${option.label}-content`} id={`panel-${option.label}-header`} > <Typography>{option.label}</Typography> </AccordionSummary> <AccordionDetails> <TransferList option={option} right={right} setRight={setRight} /> <table> <tbody> {right.map((item) => ( <tr key={item.name}> <td>{item.label}</td> </tr> ))} </tbody> </table> </AccordionDetails> </Accordion> ); return ( <> {/* 循环渲染所有筛选器 */} {options.map(option => customFilter( option, allFilters[option.name], (newValue) => updateFilter(option.name, newValue) ) )} </> ); }
关键说明
- 循环渲染时必须给每个
Accordion添加唯一key(使用option.name即可),避免React警告 updateFilter函数利用计算属性名[filterKey]动态指定要更新的状态属性,确保灵活适配新增的筛选项- 初始状态通过
reduce自动生成,后续新增options项时无需手动修改状态初始化代码
内容的提问来源于stack exchange,提问作者André Ricardo
相关产品推荐
相关产品推荐

