How to fix the count variable value in a recursive method using react and javascript?

Viewed 144

I have data like below:

const arr_obj = [
  {
    id: '1',
    children: [],
    type: 'TYPE1',
  },
  {
    id: '2',
    children: [
      {
        id: '1',
        children: [
          {
            //some attributes
          },
        ],
        type: 'MAIN',
      },
      {
        id: '2',
        children: [
          {
            //some attributes
          },
        ],
        type: 'MAIN',
      },
      {
        id: '3',
        children: [
          {
            //some attributes
          },
        ],
        type: 'MAIN',
      },
    ],
    type: 'TYPE2',
  },
  {
    id: '3',
    children: [
      {
        id: '4',
        children: [
          {
            //some attributes
          },
        ],
        type: 'MAIN',
      },
      {
        id: '5',
        children: [
          {
            //some attributes
          },
        ],
        type: 'MAIN',
      },
      {
        id: '6',
        children: [
          {
            //some attributes
          },
        ],
        type: 'MAIN',
      },
    ],
    type: 'TYPE2',
  },
];

I have to find out the count of type: 'MAIN'. these 'MAIN' will be within type: 'TYPE2'

So the expected count is 6.

below is the code,

const ParentComponent = () => {
  const findCount = (arr_obj) => {
    let count = 0;
    const expectedCount = 2;
    const loop = (children) => {
      for (const obj of children) {
        const { type, children } = obj;
        if (type === 'TYPE2') {
          loop(children);
        } else if (type === 'MAIN') {
          ++count;
          if (count > expectedCount) return;
        }
      }
    };
    loop(children);
    return count > expectedCount;
  };

  const output = findCount(arr_obj);

  return (
    //some jsx rendering
  );
};

The above code works fine, but I want to make a loop (children) function a pure function. I am not sure how to do it.

The problem now is: I define variables outside the loop method. How can I define everything as arguments to the function? You could move the function outside the component.

I have tried something like below to make it a pure function

const loop = (children, count = 0) => {
  if (!children) return;
  for (const obj of children) {
    const { type, children } = obj;
    if (type === 'TYPE2') {
      loop(children, count + 1);
    } else if (type === 'MAIN') {
      ++count;
      if (count > expectedCount) return;
    }
  }
  console.log('count', count); //this is 0 always when i log
  return count;
};

const ParentComponent = () => {
  const output = React.useMemo(() => {
    return loop(arr_obj);
  }, [arr_obj]);
  console.log('output', output); // output is always false

  return (
    //some jsx rendering
  )
};

Now the problem with above code is that the count is always 0. I am not sure where the problem is.

2 Answers

Your approach is fine: you update count by passing it as a parameter and by returning its updated value. However, the function returns at three spots and you only return count at the third spot. Furthermore, you call loop recursively, but there, you don't use its return value and you should pass count instead of count + 1 as an argument.

You need to make the following changes:

  1. Inside loop, replace return; with return count; two times.
  2. Inside loop, replace loop(children, count + 1); with count = loop(children, count);

Now, if you would remove if (count > expectedCount) return;, you would get 6 as the result.

I'm not sure what exactly you want but I don't think you'd need to make it complicated with recursion. You can simply achieve the same function like this:

const findCount = (arr) => {
  const filteredArray = arr
    .filter(el => el.type === 'TYPE2')
      // removed all elements whose type is not TYPE2
    .map(el => el.children)
      // replaced all element with element's children array
    .flat()
      // flattened the array
    .filter(el => el.type === 'MAIN');
      // removed all elements whose type is not MAIN
  return filteredArray.length;
};
Related