React组件状态更新异常:单选类切换失效问题求助
问题描述
我尝试通过切换checked-radio-btn类来显示/隐藏内容,首次点击时类能正常应用,但切换到其他元素时,前一个元素的类无法移除,希望同一时间只有一个元素处于选中状态。目前组件状态更新异常,而我正是基于这个状态来切换类的。相关组件代码如下:
function ProjectItem({ productName, totalPledge, productDescription, totalLeft, index }) { const [isActive, setIsActive] = useState('') useEffect(() => { console.log(isActive) }, [isActive]); const handleCheckedProduct = (value) => { setIsActive(value); } return ( <div className={`product ${index === isActive ? 'checked-radio-btn' : ''} ${index}`} > <input type="radio" name='product' id={productName} value={totalPledge} onClick={() => { handleCheckedProduct(index) }} /> <label className='radio-btn' htmlFor={productName} onClick={() => { handleCheckedProduct(index) }}></label> <div className='product-name'> <label htmlFor={productName} onClick={() => { handleCheckedProduct(index) }}>{productName}</label><span>Pledge ${totalPledge} or more</span> </div> <div className='product-left'> <span>{totalLeft}</span><span>left</span> </div> <div className='product-description'>{productDescription}</div> <div className={`back-product ${index === isActive ? 'checked-radio-btn' : ''}`}> <div>Enter your pledge</div> <div className='project-pledge-btn' > <div className='project-input-btn'> <input type='text' defaultValue={totalPledge} /> </div> <button>continue</button> </div> </div> </div> ) }
解决方案
问题核心在于每个ProjectItem组件都维护了自己独立的isActive状态,多个组件之间状态无法同步——选中新组件时,旧组件的状态不会被更新,所以它的checked-radio-btn类不会被移除。
要实现全局唯一选中的效果,需要把状态提升到父组件统一管理:
父组件维护选中状态
在渲染ProjectItem列表的父组件中添加状态,控制当前选中的索引:// 父组件示例代码 import { useState } from 'react'; import ProjectItem from './ProjectItem'; function ProjectList() { const [activeIndex, setActiveIndex] = useState(null); return ( <div className="project-list"> {products.map((product, index) => ( <ProjectItem key={index} {...product} index={index} isActive={index === activeIndex} onSelect={() => setActiveIndex(index)} /> ))} </div> ); }修改子组件,使用父组件传递的状态
删掉子组件自身的isActive状态,改用父组件传入的props:function ProjectItem({ productName, totalPledge, productDescription, totalLeft, index, isActive, onSelect }) { return ( <div className={`product ${isActive ? 'checked-radio-btn' : ''} ${index}`} > <input type="radio" name='product' id={productName} value={totalPledge} onClick={onSelect} checked={isActive} /> <label className='radio-btn' htmlFor={productName} onClick={onSelect}></label> <div className='product-name'> <label htmlFor={productName} onClick={onSelect}>{productName}</label><span>Pledge ${totalPledge} or more</span> </div> <div className='product-left'> <span>{totalLeft}</span><span>left</span> </div> <div className='product-description'>{productDescription}</div> <div className={`back-product ${isActive ? 'checked-radio-btn' : ''}`}> <div>Enter your pledge</div> <div className='project-pledge-btn' > <div className='project-input-btn'> <input type='text' defaultValue={totalPledge} /> </div> <button>continue</button> </div> </div> </div> ) }额外优化
给radio按钮加上checked={isActive}属性,让原生radio的选中状态和组件视觉状态保持一致,符合表单原生行为;同时移除子组件中多余的useState和useEffect,减少无意义的状态管理。
修改后所有ProjectItem的选中状态由父组件统一控制,就能保证同一时间只有一个元素带有checked-radio-btn类,实现单选效果。
内容的提问来源于stack exchange,提问作者Md Mazhar Ali
相关产品推荐
相关产品推荐

