ReactJS:在对象状态内部更新数组不会触发重新渲染

时间:2020-04-28 10:30:07

标签: javascript reactjs react-hooks state

我有一个带有状态对象apiDATA的react hooks函数。在这种状态下,我存储一个结构对象:

{
name : "MainData", description: "MainData description", id: 6, items: [
{key: "key-1", name : "Frontend-Test", description: "Only used for front end testing", values: ["awd","asd","xad","asdf", "awdr"]},
{key: "key-2", name : "name-2", description: "qleqle", values: ["bbb","aaa","sss","ccc"]},
...
]
}

我的前端将对象的主要数据显示为标题,然后映射items中的每个项目。对于这些项目,我需要显示values并使它们可编辑。我在下面附上一张图片。

enter image description here

现在您可以看到,我有一个加号按钮,可用来添加新的values。我为此使用了模态,当我调用该函数以更新状态时,它可以正常工作并正确地重新渲染。现在,对于values中的每个单词,我都拥有旁边带有删除按钮的筹码。该按钮的删除功能如下:

const deleteItemFromConfig = (word, item) => {
    const index = apiDATA.items.findIndex((x) => x.key === item.key);

    let newValues = item.value.filter((keyWord) => keyWord !== word);

    item.value = [...newValues];

    api.updateConfig(item).then((res) => {
      if (res.result.status === 200) {
        let apiDataItems = [...apiDATA.items];
        apiDataItems.splice(index, 1);
        apiDataItems.splice(index, 0, item);
        apiDATA.items = [...apiDataItems];
        setApiDATA(apiDATA);
      }
    });
  };

不幸的是,当我更新状态时,此功能不会重新呈现。而且只有当我更新其他状态时,它才会重新渲染。我知道代码有点烂,但是我尝试了一些尝试来重新渲染它,但我无法解决。我知道这与React没有把它看作是一个适当的更新有关,所以它不会重新渲染,但我不知道为什么。

2 个答案:

答案 0 :(得分:3)

它没有更新,因为您正在更改items内的数组apiDATA,并且React仅在指向apiDATA的指针改变时才重新渲染。 React不会比较apiDATA中的所有项目。

您必须创建一个新的apiDATA才能进行React更新。

尝试一下:

      if (res.result.status === 200) {
        let apiDataItems = [...apiDATA.items];
        apiDataItems.splice(index, 1);
        apiDataItems.splice(index, 0, item);
        setApiDATA(prevState => {
            return {
                ...prevState,
                items: apiDataItems
            }
       });
      }

答案 1 :(得分:0)

使用splice并不是一个好主意,因为它会改变数组的位置,即使您通过let apiDataItems = [...apiDATA.items];创建一个副本,它仍然是浅表副本,其原始引用了嵌套值。

其中一种选择是使用map更新数据:

const deleteItemFromConfig = (word, item) => {
  api.updateConfig(item).then((res) => {
    if (res.result.status === 200) {
      const items = apiDATA.items.map(it => {
        if (it.key === item.key) {
          return {
            ...item,
            values: item.value.filter((keyWord) => keyWord !== word)
          }
        }
        return item;
      })

      setApiDATA(apiData => ({...apiData, items});
    }
  });
}