title: How to remove children objects recursively from object?
body: <p>I am working on solution</p>
  <p>I have created basic tree kind of table whenever user click on expand data related to clicked row will appear under it based on row data</p>
  <p>I have achieved basic functionality of expand/collapse upto N nested levels.</p>
  <p>But i am stuck with only one problem, so basically all row have conditional expand button based on array having multiple values</p>
  <p>Lets say it is split array having 3 entries county,city,state</p>
  <p>Default loaded data will be fetched from api, now i have to check array that is there any split available! if yes than i make expand button visible</p>
  <p>Consider this scenario</p>
  <pre><code>const split = [&quot;country&quot;,&quot;city&quot;,&quot;state&quot;]
  </code></pre>
  <p>this is Ui will look like</p>
  <pre><code>+ Data_1
  + Data_2
  </code></pre>
  <p>on click of button + new data table row will be rendered based on next split available in our case it is country so visual representation will be like</p>
  <pre><code>- Data_1
     Country_1
     Country_2
  + Data_2
  </code></pre>
  <p>Here country does not have expand button as user have not added next split yet, lets add city, and assume user have clicked Country_1 so data will be like</p>
  <pre><code>    - Data_1
         - Country_1
             City_1
             City_2
         + Country_2
      + Data_2
  </code></pre>
  <p>My solution works fine till this level now lets say user have removed country from split that all nodes of country and city should be removed and - icon of data_1 should be changed to +</p>
  <p>Here is my code</p>
  <pre><code>import React, {useState, useEffect, useRef, Fragment} from &quot;react&quot;;
    import _ from &quot;lodash&quot;;
    import axios from &quot;axios&quot;;
  
    class TableRowData extends React.Component {
      state = {
        showIcon: false,
        selection: [],
        data: [],
        splitOption: [&quot;campid&quot;]
      };
      constructor(props) {
        super(props);
      }
  
      componentDidMount() {
        const checkIfSplitExistOnMount = (currentSplit) =&gt; {
          const i = _.findIndex(this.state.splitOption, function(el) {
            return el === currentSplit;
          });
  
          if (this.state.splitOption[i + 1]) {
            return this.state.splitOption[i + 1];
          } else {
              return null;
          }
        }
        const getReportData = () =&gt; {
          axios.get(&quot;https://jsonplaceholder.typicode.com/users?_start=0&amp;_limit=1&quot;).then((res) =&gt; {
            const rowData = res.data.map((row) =&gt; {
              row.name = this.state.splitOption[0];
              row.isExpanded = false;
              row.currentSplit = this.state.splitOption[0];
              row.nextSplit = checkIfSplitExistOnMount(this.state.splitOption[0])
              row.parentId = 0;
              row.isVisble = true;
              //console.log(row)
              return row;
            });
            this.setState({
              data: rowData
            }, () =&gt; { //console.log(this.state.data)
            });
          });
        }
        getReportData()
      }
  
      render() {
        // update state function
        const updateState = () =&gt; {
          this.setState({
            data: [...this.state.data],
            splitOption: [...this.state.splitOption],
            selection: [...this.state.selection],
          }, () =&gt; {})
        }
  
        // recusively update parent and child
        const recursion = (obj) =&gt; {
           let row = obj;
           row.isExpanded = row.isExpanded;
           row.currentSplit = row.currentSplit;
           row.nextSplit = checkIfSplitExist(row.currentSplit)
  
           if (row.children &amp;&amp; row.children.length &gt; 0) { // check if has children
              row.children.forEach(v =&gt; { // if has children do the same recursion for every children
                recursion(v);
              });
           }
           return row; // return final new object
         }
  
         const recursionDel = (obj,split) =&gt; {
             var row = obj;
             row.currentSplit = row.currentSplit;
             row.nextSplit = checkIfSplitExist(row.currentSplit)
             if (row.children &amp;&amp; row.children.length &gt; 0) { // check if has children
               row.children.forEach(v =&gt; { // if has children do the same recursion for every children
                 recursionDel(v);
               });
            }
            return row; // return final new object
          }
  
        // function to check if next split is there or not if there than return nextsplit
        const checkIfSplitExist = (currentSplit) =&gt; {
          const i = _.findIndex(this.state.splitOption, function(el) {
            return el === currentSplit;
          });
          if(i !== -1) {
            if (this.state.splitOption[i + 1]) {
              return this.state.splitOption[i + 1];
             } else {
              return null;
            }
          }
  
        }
  
        // recursive update whenever split added
        const recursiveUpdate = (data) =&gt; {
          const prevData = [...data];
          return prevData.map((row) =&gt; {
            const updatedData =  recursion(row);
            return row;
          });
        }
  
        // function to delete child and parent node recursively
        const recursiveDelete = (data,split) =&gt; {
          const prevData = [...data];
          return prevData.map((row) =&gt; {
            const data =  recursionDel(row,split);
            return row;
          });
        }
  
        const addNewSplit = (split) =&gt; {
          const i = _.findIndex(this.state.splitOption, function(el) {
            return el === split;
          });
          if(i === -1) {
              this.setState(
                {
                  splitOption:[...this.state.splitOption,split]
                },
                ()=&gt;{
                  var rowData = recursiveUpdate(this.state.data)
                  this.setState({data:rowData})
                }
            );
          } else {
            const prevData = [...this.state.splitOption];
            var index = prevData.indexOf(split);
            prevData.splice(index,1)
            if(index!==-1) {
              this.setState(
                  {
                      splitOption:prevData
                  },
                  ()=&gt; {
                    var rowData = recursiveDelete(this.state.data,split)
                    this.setState({data:rowData})
                  }
                )
            }
          }
  
        }
  
        // add lazyload expand data
        const ExpandableTableRow = ({rows}) =&gt; {
  
          const expandRow = (row) =&gt; {
            row.children = [
              {
                id: &quot;_&quot; + Math.random().toString(36).substr(2, 5),
                name: row.id + &quot;_&quot; + row.nextSplit,
                isExpanded: false,
                parentId: row.id,
                currentSplit: row.nextSplit,
                nextSplit: checkIfSplitExist(row.nextSplit),
                isVisble:true
              }, {
                id: &quot;_&quot; + Math.random().toString(36).substr(2, 5),
                name: row.id + &quot;_&quot; + row.nextSplit,
                isExpanded: false,
                parentId: row.id,
                currentSplit: row.nextSplit,
                nextSplit: checkIfSplitExist(row.nextSplit),
                isVisble:true
              }
            ];
            row.isExpanded = true;
            updateState();
          };
  
          // call whenever - click
          const collapseRow = (row) =&gt; {
            delete row.children;
            row.isExpanded = false;
            updateState();
          };
  
          // toggle
          const ExpandCollapsToggle = ({row, expandRow, collapseRow}) =&gt; {
            // display +/- only if nextsplit is not undefined or null
            if (row.nextSplit) {
              if (row.isExpanded === true) {
                return (&lt;button type=&quot;button&quot; onClick={() =&gt; collapseRow(row)}&gt;
                  -
                &lt;/button&gt;);
              } else {
                return (&lt;button type=&quot;button&quot; onClick={() =&gt; expandRow(row)}&gt;
                  +
                &lt;/button&gt;);
              }
            } else {
              return null;
            }
          };
  
  
  
          if (rows) {
            return rows.map((row) =&gt; {
            //  if(!_.isEmpty(row)) {
                return (&lt;Fragment key={row.id}&gt;
                  &lt;tr key={row.id}&gt;
                    &lt;td&gt;
                      &lt;ExpandCollapsToggle row={row} expandRow={expandRow} collapseRow={collapseRow}/&gt;{&quot; &quot;}
                      {row.split}
                      - {row.id}
                    &lt;/td&gt;
                    &lt;td&gt;{row.name}&lt;/td&gt;
                  &lt;/tr&gt;
                  &lt;ExpandableTableRow rows={row.children}/&gt;
                &lt;/Fragment&gt;);
            //  }
  
            });
          } else {
            return null;
          }
        };
  
        const splitData = this.state.splitOption.map((ob) =&gt; {
          return (&lt;Fragment key={ob}&gt;&lt;span&gt;{ob}&lt;/span&gt; &gt; &lt;/Fragment&gt;)
        })
  
        if (this.state.data) {
          return (
            &lt;Fragment&gt;
              {splitData} &lt;br/&gt;
              &lt;button onClick = {()=&gt;addNewSplit(&quot;name&quot;)}&gt;camp name&lt;/button&gt;
              &lt;button onClick = {()=&gt;addNewSplit(&quot;os&quot;)}&gt;os&lt;/button&gt;
              &lt;button onClick = {()=&gt;addNewSplit(&quot;country&quot;)}&gt;country&lt;/button&gt;
            &lt;ExpandableTableRow rows={this.state.data} /&gt;
          &lt;/Fragment&gt;
          );
        } else {
          return null;
        }
      }
    }
  
    export default TableRowData;
  </code></pre>
  <p>Also i have create example of codesandbox.io - <a href="https://codesandbox.io/s/confident-cookies-0qv38" rel="nofollow noreferrer">Link</a></p>
  <p>Here is how you play with ui to replicate scenario</p>
  <ul>
  <li>First click on camp name, expand icon will appear</li>
  <li>Now expand if you want to, you can see data according split under</li>
  <li>Now add one more split OS or Country and you can see expand icon with 2nd level rows</li>
  <li>Next step is to remove &quot;Camp Name&quot;, Here is issue when camp name is removed, table should be re render according available splits, in our case user's all row should be removed and + icon must be there are we have next split os or country available, i used default split id, it will be there always</li>
  </ul>