React实现点击组件仅当前项高亮 其余项取消背景色
实现方案
核心问题
当前每个Row组件的激活状态isActive由组件内部独立维护,各个Row之间状态完全隔离,无法感知其他组件的点击行为,因此无法实现互斥高亮效果。
要实现需求只需要遵循React的状态提升原则:将多个组件需要共享的状态上移到最近的共同父组件统一管控。
具体代码实现
1. 改造Row组件
移除Row内部自维护的isActive状态,将激活状态、点击事件回调、唯一标识通过props传入:
const Row = ({ isActive, onRowClick, rowId }) => { return ( <div style={{ backgroundColor: isActive ? 'green' : '#c8c7c5', padding: '12px', margin: '8px 0', cursor: 'pointer' }} onClick={() => onRowClick(rowId)} > hello </div> ); };
2. 改造父组件逻辑
不要提前把渲染完成的React元素存在state中,仅保留列表纯配置数据,由父组件统一维护当前激活项的ID,渲染列表时动态为每个Row传入对应props:
const ListContainer = () => { // 仅存储列表项配置,不要预存组件 const itemsConfig = [ { id: 'list-1' }, { id: 'list-2' }, { id: 'list-3' } ]; // 统一管理当前激活的行ID,初始为null表示无高亮项 const [activeRowId, setActiveRowId] = React.useState(null); // 统一处理行点击逻辑 const handleRowClick = (clickedId) => { setActiveRowId(currentId => { // 点击已激活的行则取消高亮,保留原有的二次点击恢复默认的交互 if (currentId === clickedId) return null; // 否则更新激活ID为当前点击项,其余项自动失活 return clickedId; }) } return ( <div className="list-wrapper"> {itemsConfig.map(item => ( <Row key={item.id} rowId={item.id} isActive={activeRowId === item.id} onRowClick={handleRowClick} /> ))} </div> ) }
实现说明
- 所有Row的激活判断逻辑统一由父组件的
activeRowId控制,每次点击任意Row都会触发父组件状态更新,所有Row会根据最新的activeRowId重新计算自身的高亮状态,天然实现互斥效果 - 提前将
<Row />这类React元素存入state/变量的写法不推荐,预创建的组件无法接收动态变化的props,列表场景仅需要存储纯配置数据,在渲染阶段动态生成组件即可 - 逻辑保留了原有交互:点击已高亮的Row会取消高亮,恢复默认背景
内容的提问来源于stack exchange,提问作者san
相关产品推荐
相关产品推荐

