You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 22:41:05