admin管理员组

文章数量:1402813

I have a react hooks function that has a state object apiDATA. In this state I store an object of structure:

{
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"]},
...
]
}

My front end displays the main data form the object as the headers and then I map each item in items. For each of these items I need to display the valuesand make them editable. I attached a picture below.

Now as you can see I have a plus button that I use to add new values. I'm using a modal for that and when I call the function to update state it does it fine and re-renders properly. Now for each of the words in the valuesI have that chip with the delete button on their side. And the delete function for that button is as follows:

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);
      }
    });
  };

Unfortunately this function does not re-render when I update state. And it only re-renders when I update some other state. I know the code is a bit crappy but I tried a few things to make it re-render and I can't get around it. I know it has something to do with React not seeing this as a proper update so it doesn't re-render but I have no idea why.

I have a react hooks function that has a state object apiDATA. In this state I store an object of structure:

{
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"]},
...
]
}

My front end displays the main data form the object as the headers and then I map each item in items. For each of these items I need to display the valuesand make them editable. I attached a picture below.

Now as you can see I have a plus button that I use to add new values. I'm using a modal for that and when I call the function to update state it does it fine and re-renders properly. Now for each of the words in the valuesI have that chip with the delete button on their side. And the delete function for that button is as follows:

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);
      }
    });
  };

Unfortunately this function does not re-render when I update state. And it only re-renders when I update some other state. I know the code is a bit crappy but I tried a few things to make it re-render and I can't get around it. I know it has something to do with React not seeing this as a proper update so it doesn't re-render but I have no idea why.

Share Improve this question asked Apr 28, 2020 at 10:30 George PontaGeorge Ponta 3133 silver badges16 bronze badges 2
  • FWIW, you only need a single .splice call: apiDataItems.splice(index, 1, item); – Felix Kling Commented Apr 28, 2020 at 10:40
  • Yes I had that before but I just broke it down hoping it will do something :)). Thank you for the observation anyways. – George Ponta Commented Apr 28, 2020 at 10:41
Add a ment  | 

2 Answers 2

Reset to default 8

It is not updating because you are changing the array items inside apiDATA, and React only re-render if the pointer to apiDATA changes. React does not pare all items inside the apiDATA.

You have to create a new apiDATA to make React updates.

Try this:

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

Using splice isn't a good idea, since it mutates the arrays in place and even if you create a copy via let apiDataItems = [...apiDATA.items];, it's still a shallow copy that has original reference to the nested values.

One of the options is to update your data with 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});
    }
  });
}

本文标签: javascriptReactJS Updating array inside object state doesn39t trigger rerenderStack Overflow