Reactdev Reactdev
Reactdev Reactdev

Reputation: 11

Update state of nested array with React Hooks

I have been working with React Hooks for a while, but the biggest problem for me is working with arrays.

How to update value of nested array of objects? I want to change dropdown type. My code is below and changes the state directly. How can I fix this? What is the most correct code?

Thanks for your help.

  const [grups, setGrups] = useState([
    {
      id: 1,
      css: "col",
      components: [
        { id: 1, type: "textbox" },
        { id: 2, type: "integer" },
      ],
    },

    {
      id: 2,
      css: "col",
      components: [
        { id: 1, type: "numerictextbox" },
        **{ id: 2, type: "dropdown" },**
      ],
    },
  ]);


 function handleClick(gindex,cindex) {
    const newgrups = [...grups];
    newgrups[gindex] = {...grups[gindex] ,components: [...grups[gindex].components]};
    newgrups[gindex].components[cindex].tip="datetime";
    setGrups(newgrups);

  }

Upvotes: 1

Views: 1222

Answers (2)

Gabriele Petrioli
Gabriele Petrioli

Reputation: 195952

So you need something like

function handleClick(gindex, cindex) {
  // use map to create a new array and at the same time
  // modify the contents when required
  const newgrups = grups.map((grup, gidx) => {
    // if the index is not the one we want return the while grup as is
    if (gidx !== gindex) return grup;
    // otherwise create a new one by spreading the existing
    return {
      ...grup,
      // and override the prop which is changed
      components: grup.components.map((component, cidx) => {
        // again if the component is not the one we want to update
        // return it as is
        if (cidx !== cindex) return component;
        // otherwise create a new one by spreading the existing
        // and adding/modifying the props we want
        return {
          ...component,
          tip: 'datetime'
        }
      })
    }
  });

  setGrups(newgrups);
}

If you just want to go with the code you have, you just need to create a new component as well

newgrups[gindex].components[cindex] = { ...newgrups[gindex].components[cindex],
  tip: 'datetime'
}

Upvotes: 1

Gegenwind
Gegenwind

Reputation: 1428

It is good practice to design your state as you would design a database. In a database normalised design is recommended because you can't just nest states in other states. In your case you could split the state in the same way:

grups

[
    {
      id: 1,
      css: "col"
    },

    {
      id: 2,
      css: "col"
    }
];

components

[
        { grups_id: 1, id: 1, type: "textbox" },
        { grups_id: 1, id: 2, type: "integer" },
        { grups_id: 2, id: 1, type: "numerictextbox" },
        { grups_id: 2, id: 2, type: "dropdown" }
]

This makes it significantly easier to handle the state and avoid nesting and complex procedues. You can easily work with components by applying componenents.filter() and filter by grups_id.

Upvotes: 0

Related Questions