React列表元素点击样式切换求助:单选及多选样式修改
Fixing React List Item Selection (Single & Multiple)
Hey there! Let's get this sorted out. The issue you're seeing right now is because you're using a single boolean state (colorDefault) to control the style of all list items. When you click any item, you flip that global state, so every element updates its style at the same time—definitely not what you want!
Solution 1: Single Item Selection
First, let's fix the single-selection case, where clicking one item highlights it and unhighlights any previously selected item.
Key Changes:
- Replace the
colorDefaultstate with aselectedIdstate that stores the ID of the currently selected item (start withnullfor no selection). - When clicking an item, update
selectedIdto the clicked item's ID (or clear it if you click the same item again). - For each list item, check if its ID matches
selectedIdto apply the active style.
Updated Code:
const nodes = [ {id: 0, name: 'aaa', parent: null }, {id: 1, name: 'bbb', parent: 0 }, {id: 2, name: 'ccc', parent: 0 }, {id: 3, name: 'ddd', parent: null }, {id: 4, name: 'eee', parent: 3 }, {id: 5, name: 'fff', parent: 3 }, {id: 6, name: 'ggg', parent: 3 }, {id: 7, name: 'hhh', parent: null }, {id: 8, name: 'iii', parent: 7 }, {id: 9, name: 'jjj', parent: 8 }, {id: 10, name: 'kkk', parent: 9 }, {id: 11, name: 'lll', parent: 9 }, {id: 12, name: 'mmm', parent: 9 }, {id: 13, name: 'nnn', parent: 8 }, {id: 14, name: 'ooo', parent: 13 }, {id: 15, name: 'ppp', parent: 13 }, {id: 16, name: 'qqq', parent: 13 }, {id: 17, name: 'rrr', parent: null }, {id: 18, name: 'sss', parent: 17 }, {id: 19, name: 'ttt', parent: 17 }, {id: 20, name: 'uuu', parent: 19 }, {id: 21, name: 'vvv', parent: 19 }, {id: 22, name: 'www', parent: 17 }, {id: 23, name: 'xxx', parent: 17 }, {id: 24, name: 'yyy', parent: 23 }, {id: 25, name: 'zzz', parent: 23 } ]; class App extends React.Component { constructor(){ super(); // Track the selected item's ID instead of a global boolean this.state = { selectedId: null } } handleSelect = (id) => { // Toggle selection: if same item is clicked, clear selection this.setState(prevState => ({ selectedId: prevState.selectedId === id ? null : id })); } render(){ const nodeColorBlue = {color: '#00f'}; const nodeColorDefault = {color: '#000'}; const renderNodes = nodes.map(node => { // Apply blue style only if this node's ID matches selectedId const itemStyle = node.id === this.state.selectedId ? nodeColorBlue : nodeColorDefault; return ( <li key={node.id} style={itemStyle} onClick={() => this.handleSelect(node.id)} > {node.name} </li> ); }); return ( <div className="App"> <ul>{renderNodes}</ul> </div> ) } } export default App;
Solution 2: Multiple Item Selection
For selecting multiple items (toggle selection on click), we'll use a Set to track all selected IDs—Sets make adding/removing items quick and efficient.
Key Changes:
- Use a
selectedIdsstate initialized as an emptySet. - On click, toggle the ID in the Set: if it's already present, remove it; if not, add it.
- Check if the current node's ID is in the
selectedIdsSet to apply the active style.
Updated Code:
const nodes = [ {id: 0, name: 'aaa', parent: null }, {id: 1, name: 'bbb', parent: 0 }, {id: 2, name: 'ccc', parent: 0 }, {id: 3, name: 'ddd', parent: null }, {id: 4, name: 'eee', parent: 3 }, {id: 5, name: 'fff', parent: 3 }, {id: 6, name: 'ggg', parent: 3 }, {id: 7, name: 'hhh', parent: null }, {id: 8, name: 'iii', parent: 7 }, {id: 9, name: 'jjj', parent: 8 }, {id: 10, name: 'kkk', parent: 9 }, {id: 11, name: 'lll', parent: 9 }, {id: 12, name: 'mmm', parent: 9 }, {id: 13, name: 'nnn', parent: 8 }, {id: 14, name: 'ooo', parent: 13 }, {id: 15, name: 'ppp', parent: 13 }, {id: 16, name: 'qqq', parent: 13 }, {id: 17, name: 'rrr', parent: null }, {id: 18, name: 'sss', parent: 17 }, {id: 19, name: 'ttt', parent: 17 }, {id: 20, name: 'uuu', parent: 19 }, {id: 21, name: 'vvv', parent: 19 }, {id: 22, name: 'www', parent: 17 }, {id: 23, name: 'xxx', parent: 17 }, {id: 24, name: 'yyy', parent: 23 }, {id: 25, name: 'zzz', parent: 23 } ]; class App extends React.Component { constructor(){ super(); // Use a Set to track multiple selected IDs this.state = { selectedIds: new Set() } } handleToggleSelect = (id) => { this.setState(prevState => { const newSelectedIds = new Set(prevState.selectedIds); if (newSelectedIds.has(id)) { newSelectedIds.delete(id); } else { newSelectedIds.add(id); } return { selectedIds: newSelectedIds }; }); } render(){ const nodeColorBlue = {color: '#00f'}; const nodeColorDefault = {color: '#000'}; const renderNodes = nodes.map(node => { // Apply blue style if the node's ID is in the selectedIds Set const itemStyle = this.state.selectedIds.has(node.id) ? nodeColorBlue : nodeColorDefault; return ( <li key={node.id} style={itemStyle} onClick={() => this.handleToggleSelect(node.id)} > {node.name} </li> ); }); return ( <div className="App"> <ul>{renderNodes}</ul> </div> ) } } export default App;
Quick Notes:
- I switched to arrow functions for event handlers to avoid needing
.bind(this)—it's a cleaner approach in class components. - For multiple selection, you could also use an array instead of a Set, but Sets are better for checking membership (
has()runs in constant time, vs arrayincludes()which checks every element).
内容的提问来源于stack exchange,提问作者pilar torres
相关产品推荐
相关产品推荐

