Home > OS >  Modify state with multiple nested children in React
Modify state with multiple nested children in React

Time:05-24

I'm trying to build a component which works like a selection tree, but with the possibility for users to edit each row in the selection tree.

Basically, a component where you can keep drilling down to get more details.

The data is structured like a nested object, where an item with drilldown possibilities has a children as per below.

  const [categories, setCategories] = useState([
    {
      name: "First Tier",
      identifier: "1",
      children: [
        {
          name: "Second Tier",
          identifier: "2",
          children: [
            {
              name: "Third Tier",
              identifier: "3",
              children: [
                {
                  name: "Fourth Tier",
                  identifier: "4",
                  children: [{ name: "Fifth Tier", identifier: "5" }],
                },
              ],
            },
          ],
        },
      ],
    },
    { name: "Another top tier", identifier: "6" },
    { name: "a Third top tier", identifier: "7" },
  ]);

My challenge is that I can't seem to find a way to modify the child and the props as I wish. As an example, I would like to be able to modify the name of the fifth child to some random name. Note - I wish to be able to modify whatever child, and I will have the identifier available.

As I'm using react, it needs to be done using "useState", which makes it a little bit more tricky according to my understanding.

Any ideas or anyone been through this challenge?

CodePudding user response:

Presented below is one possible way to achieve the desired objective.

Code Snippet

const findAndUpdate = (id, val, arr) => {
  // find 'arr' element with matching identifier
  const tgtObj = arr.find(
    ({ identifier }) => identifier === id
  );
  if (tgtObj) {             // found identifier, so update the name
    tgtObj.name = val;      // this will mutate the original array passed as argument
  } else {                  // not found, recurse through 'children' array
    arr.filter(el => 'children' in el).forEach(
      ({ children }) => findAndUpdate(id, val, children)
    );
  };
  return arr;               // in all cases, return 'arr' as-is
};

const stateArr = [
    {
      name: "First Tier",
      identifier: "1",
      children: [
        {
          name: "Second Tier",
          identifier: "2",
          children: [
            {
              name: "Third Tier",
              identifier: "3",
              children: [
                {
                  name: "Fourth Tier",
                  identifier: "4",
                  children: [{ name: "Fifth Tier", identifier: "5" }],
                },
              ],
            },
          ],
        },
      ],
    },
    { name: "Another top tier", identifier: "6" },
    { name: "a Third top tier", identifier: "7" },
  ];

// the 'stateArr' will be mutated by using this method
console.log(
  'find id: 5 and update name: "New Fifth Tier"... ',
  findAndUpdate("5", "New Fifth Tier", stateArr)
);

// to call this using "setCategories", simply try this:
/*
setCategories(prev => findAndUpdate("5", "New Fifth Tier", prev));
*/
.as-console-wrapper { max-height: 100% !important; top: 0 }

Explanation

Inline comments added to the snippet above.

  • Related