useState更新状态子数组对象不起作用

时间:2019-11-08 22:34:39

标签: javascript reactjs ecmascript-6

我的React组件中有此状态->

const [employeeState, setEmployee] = useState({
        "empName": null,
        "Age": null,
        "depts": [], //depts is an array of objects
        "groups": [] //group is an array of objects
});

我对部门和小组有单独的状态,如下所示->

const depts = {
        "name": "some name",
        "code": "s123",
}
const [deptState, setDeptState] = useState([
        { ...depts},
]);

团体也一样。...

现在,当我尝试在某些btn点击上设置员工状态时,如下所示,它没有更新并保持deptsgroups属性为空->

const deptsLst = [...deptState];
const groupsLst = [...groupstate];
console.log(depsLst); // this will print the results as expected
console.log(groupsLst); // this will print the results as expected
setEmployee({
      ...employeeState,
      ['depts']: deptsLst ,
      ['groups']: groupsLst ,
})
 console.log(employeeState);// this will show depts and groups as empty only

我对这种传播变量复制概念并不陌生。我在这里做什么错了?

3 个答案:

答案 0 :(得分:1)

您可以这样做:

setEmployee({
  ...employeeState,
  depts: deptsLst,
  groups: groupsLst
})

更新您的employeeState。之后,您可能不会看到带有console.log的更新,因为它将在状态更新之前执行。您可以使用以下employeeState函数来验证useEffect是否已更新:

  useEffect(() => {
    console.log(employeeState)
  }, [employeeState])

spread运算符是ES6复制阵列的一种方式,无需传递对副本的引用,因此您可以修改一个阵列而不会在其他阵列中显示这些更改。您可以在这里进一步了解:Reference And Copying Objects & Arrays

答案 1 :(得分:1)

您声明“我不是这个传播变量复制概念的新手” ...不仅是传播操作的新手,而且您的代码表明您对它没有基本的了解。您无缘无故地在计算机属性名称的顶部使用了扩展运算符。

您还使用React状态来管理雇员对象,然后使用React状态来管理雇员对象上的Array属性。如果您已经在对employee对象执行状态管理,为什么要维护单个属性的状态?

确定代码的几个细目:

const depts = {
        "name": "some name",
        "code": "s123",
}
const [deptState, setDeptState] = useState([
        { ...depts},
]);

上面您无缘无故地克隆对象。

使用React状态管理,您只需克隆对象即可触发渲染事件。克隆将在内存中创建一个具有新引用的新对象,将“响应”对象引用更改并触发状态更改事件。 React无法监视复杂对象的每个属性,尤其是数组元素,以查看值是否已更改。

下面的代码就足够了,您正在初始化状态,无需克隆:

const [deptState, setDeptState] = useState([{
        "name": "some name",
        "code": "s123",
}]);

接下来的代码:

setEmployee({
      ...employeeState,
      ['depts']: deptsLst ,
      ['groups']: groupsLst ,
})

在这里,您尝试使用传播运算符来克隆“ employeeState”对象,并更新depts属性键和groups属性键的新值。您无缘无故地将“计算出的属性名称”用作属性键。

这就足够了:

setEmployee({
      ...employeeState,
      depts: deptsLst ,
      groups: groupsLst
})

您还会创建不必要的状态:

const [deptState, setDeptState] = //..rest of code omitted

在这里您没有意识到React状态更改是异步发生的:

setEmployee({
      ...employeeState,
      ['depts']: deptsLst ,
      ['groups']: groupsLst ,
})
console.log(employeeState);

上面的代码实际上已经更改了employeeState,只是不是您的console.log(employeeState)的时间;

好的,首先,我有created a CodePen供您了解状态如何变化。

当您要更改此雇员对象的状态时,只需更改对象属性值或添加新属性值,然后克隆雇员对象以更改其引用,然后使用克隆调用setState,请考虑使用此对象状态:

const [employee, setEmployee] = React.useState({
    "empName": 'Jane Doe',
    "Age": 33,
    "depts": [
        {
            "name": "some name",
            "code": "s123",
        }
    ]
});

这里我要向员工添加部门,请注意,我仅克隆员工对象以触发React来检测总体对象引用更改,React不知道我更改了属性depts数组,但是新状态确实具有我在部门数组上施加的新值:

function exampleUpdatingEmployee() {
    employee.depts.push({
        "name": "some new dept",
        "code": "876",
    });
    setEmployee({ ...employee });
}

答案 2 :(得分:0)

如果depts和group是对象数组,则应使用散布运算符以这种方式复制值:

setEmployee({
      ...employeeState,
      depts: [...deptState],
      groups: [...groupstate]
});

所以如果:

const employeeState = {status: 'hungry'};
const deptState = ['one', 'two'];
const groupstate = ['y', 'k', 'o'];

然后,散布后的第一个代码如下:

setEmployee({
   status: 'hungry',
   depts: ['one', 'two'],
   groups: ['y', 'k', 'o']
});