如何在遍历未知长度数组时实现每行仅选一个MUI ToggleButton
问题描述
我正在用MUI和React做赛事选择组件,每个赛事行(主胜、平局、客胜)用ToggleButton展示,要求每行只能选一个选项。赛事每周都会变,数量也不固定。
默认的ToggleButtonGroup是全局只能选一个,我把exclusive改成false后,虽然支持数组,但用户能在同一行选多个结果,不符合需求。
怎么加逻辑实现每行独立单选?
注意:赛事数据来自数据库调用,下面的fixtures数组是返回数据的示例。
用户原代码:
const [fixtures, SetFixtures] = useState([{ gameweek: "loading...", game: "loading...", home: "loading...", away: "loading...", draw: "loading...", kickoff_datetime: "loading...", result: "loading...", }]); const [alignment, setAlignment] = useState([]); const handleChange = (newAlignment) => { setAlignment(newAlignment); }; const fixtures = [ { game: "LeicesterArsenal", gameweek: 2, home: "Leicester", away: "Arsenal", draw:"LeicesterArsenalDraw", kickoff_datetime: "2022-07-15T15:30:00", result: null }, { game: "ManchesterUnitedNottinghamForest", game: 2, home: "Manchester United", away: "Nottingham Forest", draw:"ManchesterUnitedNottinghamForestDraw", kickoff_datetime: "2022-07-15T15:30:00", result: null }, { game: "TottenhamWestHam", game: 2, home: "Tottenham", away: "West Ham", draw:"TottenhamWestHamDraw", kickoff_datetime: "2022-07-15T15:30:00", result: null }, { game: "WolvesCrystalPalace", game: 2, home: "Wolves", away: "Crystal Palace", draw:"WolvesCrystalPalaceDraw", kickoff_datetime: "2022-07-15T15:30:00", result: null }] function RenderFixtures() { return fixtures.map((fixture, index) => <div id={"fixture-row-" + index} key={fixture.game}> <ToggleButtonGroup color="success" value={alignment} exclusive={true} onChange={handleChange} > <ToggleButton value={fixture.home}>{fixture.home}</ToggleButton> <ToggleButton value={fixture.draw}>Draw</ToggleButton> <ToggleButton value={fixture.away}>{fixture.away}</ToggleButton> </ToggleButtonGroup> </div>
解决方案
核心问题是你用了全局的alignment状态管理所有行的选中状态,导致所有ToggleButtonGroup共享同一状态。要实现每行独立单选,需给每个赛事行分配单独的状态:
- 修改状态结构:把全局数组改成对象,用赛事的唯一标识(比如
fixture.game)作为key,存储对应行的选中值 - 更新事件处理函数:让它能针对具体赛事更新状态
- 绑定每行独立状态:每个ToggleButtonGroup使用对应赛事的状态值,保持
exclusive={true}确保行内单选
修改后的完整代码示例:
import { useState } from 'react'; import { ToggleButtonGroup, ToggleButton } from '@mui/material'; const YourComponent = () => { // 初始化赛事状态,加载时显示占位内容 const [fixtures, setFixtures] = useState([{ gameweek: "loading...", game: "loading...", home: "loading...", away: "loading...", draw: "loading...", kickoff_datetime: "loading...", result: "loading...", }]); // 用对象存储每行的选中状态,key为赛事唯一标识 const [selections, setSelections] = useState({}); // 处理每行的选择变化,传入赛事唯一标识 const handleChange = (event, newSelection, fixtureKey) => { setSelections(prevState => ({ ...prevState, [fixtureKey]: newSelection || null })); }; // 示例赛事数据(实际从数据库获取后用setFixtures更新) const sampleFixtures = [ { game: "LeicesterArsenal", gameweek: 2, home: "Leicester", away: "Arsenal", draw:"LeicesterArsenalDraw", kickoff_datetime: "2022-07-15T15:30:00", result: null }, { game: "ManchesterUnitedNottinghamForest", gameweek: 2, home: "Manchester United", away: "Nottingham Forest", draw:"ManchesterUnitedNottinghamForestDraw", kickoff_datetime: "2022-07-15T15:30:00", result: null }, { game: "TottenhamWestHam", gameweek: 2, home: "Tottenham", away: "West Ham", draw:"TottenhamWestHamDraw", kickoff_datetime: "2022-07-15T15:30:00", result: null }, { game: "WolvesCrystalPalace", gameweek: 2, home: "Wolves", away: "Crystal Palace", draw:"WolvesCrystalPalaceDraw", kickoff_datetime: "2022-07-15T15:30:00", result: null } ]; // 渲染赛事行 function RenderFixtures() { return fixtures.map((fixture) => ( <div id={`fixture-row-${fixture.game}`} key={fixture.game}> <ToggleButtonGroup color="success" value={selections[fixture.game] || null} exclusive={true} onChange={(e, val) => handleChange(e, val, fixture.game)} > <ToggleButton value={fixture.home}>{fixture.home}</ToggleButton> <ToggleButton value={fixture.draw}>Draw</ToggleButton> <ToggleButton value={fixture.away}>{fixture.away}</ToggleButton> </ToggleButtonGroup> </div> )); } return ( <div> {RenderFixtures()} </div> ); }; export default YourComponent;
关键说明
- 状态
selections是对象,每个key对应一个赛事的选中值,确保各行状态独立 - 每个ToggleButtonGroup的
value绑定selections[fixture.game],只关注当前行的选中状态 handleChange通过fixtureKey精准更新对应赛事的选中值,不影响其他行- 保持
exclusive={true},确保每行内部只能选择一个选项
内容的提问来源于stack exchange,提问作者Ollie
相关产品推荐
相关产品推荐

