ReactJS复选框条件禁用问题:已选达标后需锁定未选框
问题描述
场景与需求
用户从dataset选择选项后调用API,API返回含嵌套数组的对象,数组值渲染为复选框;同时返回choose字段(常量名primaryMax),标识可勾选的复选框数量。
需求:勾选复选框时将其name存入数组,当array.length >= primaryMax时,锁定所有未勾选的复选框,但仍可取消已勾选的复选框,取消后重新启用其他复选框。
当前问题
已设置数组长度达标时禁用复选框,但所有复选框均被禁用,已勾选的未被排除;尝试在.map函数中加入decideDisabled逻辑,问题仍未解决。
现有代码
//this sets the primaryMax to the choose value //the api data starts at proficiency_choices useEffect(() => { const primaryChoices = character?.class?.primary?.proficiency_choices setPrimaryMax(primaryChoices?.choose) }, [primaryChoices]) useEffect(() => { const primaryProChoice = () => { const primaryChoices = character?.class?.primary?.proficiency_choices const secondaryChoices = character?.class?.secondary?.proficiency_choices const isEmpty = Object.keys(character?.class?.primary).length === 0 const isSecondaryEmpty = Object.keys(character?.class?.secondary).length === 0 //bard is set up differently so i excluded it and will add logic later to include it if(!isEmpty && character.class.primary.name !== 'Bard'){ console.log(primaryMax) const isDisabled = chosenProPrimary.length >= primaryMax ? true : false return setPrimaryProDiv( <div> {primaryChoices[0].desc} {primaryChoices[0].from.options.map((option, i) => { // let isChecked const handleCheck = (e) => { console.log(e) const beenChecked = e.target.checked if(beenChecked){ isChecked = true setChosenProPrimary((prevPro) => [...prevPro, e.target.name]) }else if (!beenChecked){ isChecked = false setChosenProPrimary((currentPro) => currentPro.filter((x) => x !== e.target.name)) } console.log(chosenProPrimary) } return( <p key={i}> <input type='checkbox' name={option.item.index} onChange={handleCheck} disabled={isChecked ? false : isDisabled} /> <label htmlFor={option.item.index}>{option.item.name}</label> </p> ) })} </div> ) } } primaryProChoice() //chosenProPrimary is the object selected from the dataset. it has all of the data from the api call }, [chosenProPrimary, primaryMax])
解决方案
问题核心在于用let isChecked判断选中状态的逻辑无效,这个变量无法和chosenProPrimary数组的更新同步,导致禁用规则判断错误。同时直接用状态存储JSX的做法不符合React渲染逻辑,需要调整。
修改后的代码如下:
// 保留设置primaryMax的逻辑,修正依赖项 useEffect(() => { const primaryChoices = character?.class?.primary?.proficiency_choices setPrimaryMax(primaryChoices?.choose) }, [character?.class?.primary?.proficiency_choices]) // 将渲染逻辑抽为函数,直接返回JSX而非存入状态 const renderPrimaryProChoices = () => { const primaryChoices = character?.class?.primary?.proficiency_choices const isEmpty = Object.keys(character?.class?.primary || {}).length === 0 if (!isEmpty && character.class.primary.name !== 'Bard') { return ( <div> {primaryChoices[0].desc} {primaryChoices[0].from.options.map((option, i) => { // 直接从已选数组判断当前选项是否被选中 const isChecked = chosenProPrimary.includes(option.item.index) // 修正禁用规则:已选数量达标且当前选项未被选中时才禁用 const isDisabled = chosenProPrimary.length >= primaryMax && !isChecked const handleCheck = (e) => { const { checked, name } = e.target if (checked) { setChosenProPrimary(prev => [...prev, name]) } else { setChosenProPrimary(prev => prev.filter(item => item !== name)) } } return ( <p key={i}> <input type='checkbox' name={option.item.index} onChange={handleCheck} disabled={isDisabled} checked={isChecked} // 设为受控组件,保证状态同步 /> <label htmlFor={option.item.index}>{option.item.name}</label> </p> ) })} </div> ) } return null } // 在组件渲染时调用该函数 return ( <div> {renderPrimaryProChoices()} </div> )
关键修改点:
- 用
chosenProPrimary.includes(option.item.index)替代局部变量判断选中状态,确保和已选数组完全同步 - 调整
isDisabled逻辑:仅当已选数量达到上限且当前选项未被选中时禁用 - 将复选框改为受控组件,显式设置
checked属性,避免状态不一致 - 移除用
setPrimaryProDiv存储JSX的做法,直接在渲染逻辑中返回内容,符合React数据流模式
内容的提问来源于stack exchange,提问作者Christopher Dirksen
相关产品推荐
相关产品推荐

