【问题标题】:oksetState functions is not updated in react hooksoksetState 函数未在反应挂钩中更新
【发布时间】:2026-01-15 21:35:01
【问题描述】:

我通过下拉按钮选择没有用户后呈现多个表单, 我正在为这些生成的用户动态生成帮助文本和用户数据状态。

这是我初始化状态对象的地方

const [selectedIndex, setSelectedIndex] = React.useState(0);
const [registrationData,setRegistrationData]=React.useState([]);
const [error,setError]=React.useState({});
const [registrations]=React.useState([]);
const [campaign, setCampaign] = React.useState({});

这是对下拉按钮的处理:

const handleMenuItemClick=(event, index)=>{
        console.log("CLicked "+(index+1))
        setSelectedIndex(index);
        setAnchorEl(null); 
};

这是使用 useEffect 动态生成状态的地方:

 useEffect(()=>{
        setCampaign(prevCampaign => ({
            ...prevCampaign,
            ...Object.assign({}, ...[...new Array(10).keys()].map(i => ({
                [i]: {
                    sms_campaign: false,
                    email_campaign: false,
                }
            })))
        }));
        setError(prevError => ({
            ...prevError,
            ...Object.assign({}, ...[...new Array(10).keys()].map(i => ({
                [i]: {
                   uscf_id:"",
                   first_name:"",
                   middle_name:"",
                   last_name:"",
                   city:"",
                   state:"",
                   country:"",
                   phone_number:"",
                   email_id:"",
                }
            })))
        }));
        setRegistrationData(prevReg => ({
            ...prevReg,
            ...Object.assign({}, ...[...new Array(10).keys()].map(i => ({
                [i]: {
                uscf_id:"",
                first_name:"",
                middle_name:"",
                last_name:"",
                sections:"",
                city:"",
                state:"",
                country:"",
                phone_code:"",
                phone_number:"",
                email_id:"",
                sms:"",
                email:""
            }
            })))
        }));
        },[selectedIndex])

这是我渲染卡片的地方:

registrations.filter((index)=>{
                    return (index<selectedIndex);
                }).map((registration,index)=>{
                    return(
                        <Card className={classes.cardLayout}>
                            <Avatar className={classes.icon}>
                                {index+1}
                            </Avatar>
                            <CardContent className={classes.cardContent}>
                            <TextField

                                id="outlined-error-helper-text"
                                label="ID"
                                name="id"
                                placeholder="Enter ID"
                                variant="outlined"
                                helperText={error[index].id}
                                error={(error[index].id===null||error[index].d==="")?false:true}
                                onChange={(event)=>updateUserdata(event,index)}
                                className={classes.textField}
                            />
.....
.....

这是处理下拉按钮的地方:

 <Button
                    aria-controls="simple-menu" 
                    aria-haspopup="true" 
                    variant="outlined" 
                    color="inherit"  
                    label="registrations"
                    style={{marginLeft:20}}
                    endIcon={<ArrowDropDownIcon/>}
                    onClick={(event)=>handleClick(event)}
                    >
                    <Typography variant="body2" color="inherit">
                    //here , I have mentioned selectedIndex+1 to just show 1 instead of 0
                        {selectedIndex+1}
                    </Typography>
                    </Button>
                        <Menu
                            id="simple-menu"
                            anchorEl={anchorEl}
                            keepMounted    
                            open={Boolean(anchorEl)}
                            onClose={handleClose}
                        >
                        {[1,2,3,4,5,6,7,8,9,10].map((option, index) => (
                            <MenuItem                                       
                                style={{paddingRight:85}}
                                key={option}
                                name="no_of_registrations"
                                selected={(index === selectedIndex)}
                                onClick={(event) => handleMenuItemClick(event, index)}
                            >
                                {option}
                            </MenuItem>
                            ))}
                        </Menu>

我也有表单验证,当用户单击注册按钮时我会调用它来执行字段检查,现在只有 selectedIndex 卡片字段正在设置错误文本,之前剩余的卡片没有设置错误文本。

const formValidation=()=>{
        console.log("entered Form validation function")
        let valid=true;
        for(var i=0;i<selectedIndex;i++){
            if(registrationData[i].id===""){
                setError((error)=>({...error,[i]:{...error[i],id:"required" }}))
                valid=false
            }else {
                if(!(registrationData[i].id).match(/^[0-9]+$/)||([registrationData[i].id].length!==10)){
                    setError((error)=>({...error,[i]:{...error[i],id:"required" }}))
                    valid=false
                }else{
                    setError((error)=>({...error,[i]:{...error[i],id:"required" }}))
                }
            }
....

【问题讨论】:

  • 是的,您可以使用多个 setState 函数。
  • 但是设置状态后状态没有更新
  • 为什么你认为设置状态后状态没有更新。你的证据是什么?
  • 请用minimal reproducible example 更新您的问题,以证明问题,最好是使用堆栈片段([&lt;&gt;] 工具栏按钮)可运行。 Stack Snippets 支持 React,包括 JSX; here's how to do one.
  • 另外,从0 开始到&lt;=selectedIndex 的循环看起来会关闭。通常循环从0 开始到&lt; 他们的上限,而不是&lt;=。但我没有足够的上下文来说明这是否真的是上述问题。

标签: javascript reactjs asynchronous react-hooks


【解决方案1】:

您必须只更新一次状态,而不是在不使用状态更新回调的情况下专门在 for 循环中更新。

您可以通过映射一个长度等于 selectedIndex 的数组来返回每个状态更新器中的对象值来执行更新

useEffect(()=>{
    setCampaign(prevCampaign => ({
        ...prevCampaign,
        ...Object.assign({}, ...[...new Array(10).keys()].map(i => ({
            [i]: {
                sms_campaign: false,
                email_campaign: false,
            }
        })))
    }));
    setError(prevError => ({
        ...prevError,
        ...Object.assign({}, ...[...new Array(10).keys()].map(i => ({
            [i]: {
               id:"",
               first_name:"",
               middle_name:"",
               last_name:"",
               city:"",
               state:"",
               country:"",
               phone_number:"",
               email_id:"",
            }
        })))
    }));
    setRegistrationData(prevReg => ({
        ...prevReg,
        ...Object.assign({}, ...[...new Array(10).keys()].map(i => ({
            [i]: {
            id:"",
            first_name:"",
            middle_name:"",
            last_name:"",
            sections:"",
            city:"",
            state:"",
            country:"",
            phone_code:"",
            phone_number:"",
            email_id:"",
            sms:"",
            email:""
        }
        })))
    }));
    },[selectedIndex])

【讨论】:

  • 我已经更新了coede,请参考并说出我的错误,请
  • 当您使用 setState 在循环中更新时,状态值会被您的上次更新覆盖,这就是为什么您应该使用带有状态更新程序的回调方法。如果您使用回调方法,您的代码也将工作, 但是设置一次状态是更好的方法
  • 好的,我会努力的,请保持在线,这对我来说很重要
  • 您的回答有点解决了我的问题,但是您的 useEffect 方法会生成 10 个对象,但我希望对于 selectedIndex 和我的错误文本仅显示所选索引卡而不是对于剩余的卡片,我已经更新了问题,请检查
  • 在这种情况下,您不需要地图或循环。删除该部分,它应该像你想要的那样工作