オブジェクトから子オブジェクトを再帰的に削除するにはどうすればよいですか?

Janak prajapati

私は解決策に取り組んでいます

ユーザーがクリックした行に関連するデータを展開すると、行データに基づいてその下に表示されるたびに、基本的なツリーの種類のテーブルを作成しました

N個のネストされたレベルまで展開/折りたたみの基本機能を実現しました。

しかし、私は1つの問題だけで立ち往生しているので、基本的にすべての行には、複数の値を持つ配列に基づく条件付き展開ボタンがあります

郡、市、州の3つのエントリを持つ分割配列であるとしましょう

デフォルトでロードされたデータはAPIからフェッチされます。次に、使用可能な分割がある配列を確認する必要があります。はいの場合、展開ボタンを表示します

このシナリオを検討してください

const split = ["country","city","state"]

これはUiが次のようになります

+ Data_1
+ Data_2

ボタンをクリックすると、新しいデータテーブルの行が、国である場合に利用可能な次の分割に基づいてレンダリングされるため、視覚的な表現は次のようになります。

- Data_1
   Country_1
   Country_2
+ Data_2

ここでは、ユーザーが次の分割をまだ追加していないため、国には展開ボタンがありません。都市を追加し、ユーザーがCountry_1をクリックしたと仮定して、データは次のようになります。

    - Data_1
       - Country_1
           City_1
           City_2
       + Country_2
    + Data_2

私のソリューションは、このレベルまで正常に機能します。ユーザーが国を分割から削除し、国と都市のすべてのノードを削除し、data_1のアイコンを+に変更する必要があるとします。

これが私のコードです

import React, {useState, useEffect, useRef, Fragment} from "react";
  import _ from "lodash";
  import axios from "axios";

  class TableRowData extends React.Component {
    state = {
      showIcon: false,
      selection: [],
      data: [],
      splitOption: ["campid"]
    };
    constructor(props) {
      super(props);
    }

    componentDidMount() {
      const checkIfSplitExistOnMount = (currentSplit) => {
        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 = () => {
        axios.get("https://jsonplaceholder.typicode.com/users?_start=0&_limit=1").then((res) => {
          const rowData = res.data.map((row) => {
            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
          }, () => { //console.log(this.state.data)
          });
        });
      }
      getReportData()
    }

    render() {
      // update state function
      const updateState = () => {
        this.setState({
          data: [...this.state.data],
          splitOption: [...this.state.splitOption],
          selection: [...this.state.selection],
        }, () => {})
      }

      // recusively update parent and child
      const recursion = (obj) => {
         let row = obj;
         row.isExpanded = row.isExpanded;
         row.currentSplit = row.currentSplit;
         row.nextSplit = checkIfSplitExist(row.currentSplit)

         if (row.children && row.children.length > 0) { // check if has children
            row.children.forEach(v => { // if has children do the same recursion for every children
              recursion(v);
            });
         }
         return row; // return final new object
       }

       const recursionDel = (obj,split) => {
           var row = obj;
           row.currentSplit = row.currentSplit;
           row.nextSplit = checkIfSplitExist(row.currentSplit)
           if (row.children && row.children.length > 0) { // check if has children
             row.children.forEach(v => { // 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) => {
        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) => {
        const prevData = [...data];
        return prevData.map((row) => {
          const updatedData =  recursion(row);
          return row;
        });
      }

      // function to delete child and parent node recursively
      const recursiveDelete = (data,split) => {
        const prevData = [...data];
        return prevData.map((row) => {
          const data =  recursionDel(row,split);
          return row;
        });
      }

      const addNewSplit = (split) => {
        const i = _.findIndex(this.state.splitOption, function(el) {
          return el === split;
        });
        if(i === -1) {
            this.setState(
              {
                splitOption:[...this.state.splitOption,split]
              },
              ()=>{
                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
                },
                ()=> {
                  var rowData = recursiveDelete(this.state.data,split)
                  this.setState({data:rowData})
                }
              )
          }
        }

      }

      // add lazyload expand data
      const ExpandableTableRow = ({rows}) => {

        const expandRow = (row) => {
          row.children = [
            {
              id: "_" + Math.random().toString(36).substr(2, 5),
              name: row.id + "_" + row.nextSplit,
              isExpanded: false,
              parentId: row.id,
              currentSplit: row.nextSplit,
              nextSplit: checkIfSplitExist(row.nextSplit),
              isVisble:true
            }, {
              id: "_" + Math.random().toString(36).substr(2, 5),
              name: row.id + "_" + 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) => {
          delete row.children;
          row.isExpanded = false;
          updateState();
        };

        // toggle
        const ExpandCollapsToggle = ({row, expandRow, collapseRow}) => {
          // display +/- only if nextsplit is not undefined or null
          if (row.nextSplit) {
            if (row.isExpanded === true) {
              return (<button type="button" onClick={() => collapseRow(row)}>
                -
              </button>);
            } else {
              return (<button type="button" onClick={() => expandRow(row)}>
                +
              </button>);
            }
          } else {
            return null;
          }
        };



        if (rows) {
          return rows.map((row) => {
          //  if(!_.isEmpty(row)) {
              return (<Fragment key={row.id}>
                <tr key={row.id}>
                  <td>
                    <ExpandCollapsToggle row={row} expandRow={expandRow} collapseRow={collapseRow}/>{" "}
                    {row.split}
                    - {row.id}
                  </td>
                  <td>{row.name}</td>
                </tr>
                <ExpandableTableRow rows={row.children}/>
              </Fragment>);
          //  }

          });
        } else {
          return null;
        }
      };

      const splitData = this.state.splitOption.map((ob) => {
        return (<Fragment key={ob}><span>{ob}</span> > </Fragment>)
      })

      if (this.state.data) {
        return (
          <Fragment>
            {splitData} <br/>
            <button onClick = {()=>addNewSplit("name")}>camp name</button>
            <button onClick = {()=>addNewSplit("os")}>os</button>
            <button onClick = {()=>addNewSplit("country")}>country</button>
          <ExpandableTableRow rows={this.state.data} />
        </Fragment>
        );
      } else {
        return null;
      }
    }
  }

  export default TableRowData;

また、codesandbox.ioの例を作成しました-リンク

シナリオを複製するためにUIで遊ぶ方法は次のとおりです

  • キャンプ名を最初にクリックすると、展開アイコンが表示されます
  • 必要に応じて展開すると、下の分割に従ってデータを表示できます
  • 次に、分割されたOSまたは国をもう1つ追加すると、2番目のレベルの行を含む展開アイコンが表示されます。
  • 次のステップは「キャンプ名」を削除することです。キャンプ名が削除されると、テーブルは利用可能な分割に従って再レンダリングされる必要があります。この場合、ユーザーのすべての行が削除され、+アイコンが次の分割OSがあるか、利用可能な国、私はデフォルトの分割IDを使用しました、それは常にそこにあります
チャンダン
import React, { useState, useEffect, useRef, Fragment } from "react";
import axios from "axios";

const test_data = [{
  "id":1,
    "name":"Leanne Graham",
    "username":"Bret",
    "email":"[email protected]",
    "address":{
      "street":"Kulas Light",
      "suite":"Apt. 556",
      "city":"Gwenborough",
      "zipcode":"92998-3874",
      "geo":{
        "lat":"-37.3159",
        "lng":"81.1496"
      }
    },
    "phone":"1-770-736-8031 x56442",
    "website":"hildegard.org",
    "company":{
      "name":"Romaguera-Crona",
      "catchPhrase":"Multi-layered client-server neural-net",
      "bs":"harness real-time e-markets"
    }
}];

class TableRowData extends React.Component {

  constructor(props) {
    super(props);

    this.state = {
      showIcon: false,
      selection: [],
      data: [],
      splitOption: ["campid"]
    };
  }

  // function to check if next split is there or not if there than return nextsplit
  checkIfSplitExist = (currentSplit) => {
    const i = this.state.splitOption.indexOf(currentSplit);

    if (i > -1 && this.state.splitOption[i + 1]) {
      return this.state.splitOption[i + 1];
    }
    return null;
  }

  getReportData = () => {
    // axios.get("https://jsonplaceholder.typicode.com/users?_start=0&_limit=1").then(({data}) => {
      this.setState({
        data: test_data.map((row) => {
        row.name = this.state.splitOption[0];
        row.isExpanded = false;
        row.currentSplit = this.state.splitOption[0];
        row.nextSplit = this.checkIfSplitExist(this.state.splitOption[0])
        row.parentId = 0;
        row.isVisble = true;
        console.log(row)
        return row;
      })
      });
    // });
  }
  
  componentDidMount() {
    this.getReportData()
  }

  render() {
    // update state function
    const updateState = () => {
      this.setState({
        data: [...this.state.data],
        splitOption: [...this.state.splitOption],
        selection: [...this.state.selection],
      }, () => { })
    }

    const recursionUpdateAndDeleteRow = (parentRow, childRow, split, index = 0) => {
      childRow.children && childRow.children.forEach((r) => {
        recursionUpdateAndDeleteRow(childRow, r, split, index + 1);
      });

      if (parentRow && split.indexOf(childRow.currentSplit) == -1) {
        delete parentRow.children;
      }

      childRow.currentSplit = split[index];
      childRow.nextSplit = split[index + 1] || null;
      if (!childRow.children) {
        childRow.isExpanded = false;
      }
    }

    const recursionUpdateAndDeleteRows = (rows, split) => {
      const _copy = [...rows];
      _copy.forEach((row) => {
        recursionUpdateAndDeleteRow(null, row, split);
      });
      return _copy;
    }

    const toggleSplit = (split) => {
      const index = this.state.splitOption.indexOf(split);
      let currentSplitOptions = [...this.state.splitOption];
      if (index > -1) {
        currentSplitOptions.splice(index, 1)
      }
      else {
        currentSplitOptions.push(split);
      }

      const _data = recursionUpdateAndDeleteRows(this.state.data, currentSplitOptions);

      this.setState({
        splitOption: currentSplitOptions,
        data: _data
      })
    }

    // add lazyload expand data
    const ExpandableTableRow = ({ rows }) => {

      const expandRow = (row) => {
        row.children = [
          {
            id: "_" + Math.random().toString(36).substr(2, 5),
            name: row.id + "_" + row.nextSplit,
            isExpanded: false,
            parentId: row.id,
            currentSplit: row.nextSplit,
            nextSplit: this.checkIfSplitExist(row.nextSplit),
            isVisble: true
          }, {
            id: "_" + Math.random().toString(36).substr(2, 5),
            name: row.id + "_" + row.nextSplit,
            isExpanded: false,
            parentId: row.id,
            currentSplit: row.nextSplit,
            nextSplit: this.checkIfSplitExist(row.nextSplit),
            isVisble: true
          }
        ];
        row.isExpanded = true;
        updateState();
      };

      // call whenever - click
      const collapseRow = (row) => {
        delete row.children;
        row.isExpanded = false;
        updateState();
      };

      // toggle
      const ExpandCollapsToggle = ({ row }) => {
        // display +/- only if nextsplit is not undefined or null
        if (row.nextSplit) {
          if (row.isExpanded) {
            return (
              <button type="button" onClick={() => collapseRow(row)}>
                -
              </button>
            );
          }
          return (
            <button type="button" onClick={() => expandRow(row)}>
              +
            </button>
          );
        }
        return null;
      };

      if (rows) {
        return rows.map((row) => {
          return (
            <Fragment key={row.id}>
            <tr key={row.id}>
              <td>
                <ExpandCollapsToggle
                  row={row}
                />
                {" "}{row.split} - {row.id}
              </td>
              <td>{row.name}</td>
            </tr>
            <ExpandableTableRow rows={row.children} />
          </Fragment>
          );
        });
      } else {
        return null;
      }
    };

    if (this.state.data) {
      return (
        <Fragment>
          {this.state.splitOption.join(', ')} <br />
          <button onClick={() => toggleSplit("name")}>
            camp name
          </button>
          <button onClick={() => toggleSplit("os")}>os</button>
          <button onClick={() => toggleSplit("country")}>country</button>
          <br />
          <ExpandableTableRow rows={this.state.data} />
        </Fragment>
      );
    } else {
      return null;
    }
  }
}

export default function App() {
  return (
    <div>
      <TableRowData />
    </div>
  );
}

ここでの作業

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

PHPオブジェクトからJSONへ:複数の再帰的な子を持つクラスを作成するにはどうすればよいですか?

分類Dev

オブジェクトをオブジェクトから別のオブジェクトに送信するにはどうすればよいですか?

分類Dev

Djangoでオブジェクトを削除から保護するにはどうすればよいですか?

分類Dev

jqを使用してサブオブジェクトをjsonオブジェクトから削除するにはどうすればよいですか?

分類Dev

Javaの配列からオブジェクトを削除するにはどうすればよいですか?

分類Dev

JavaScriptオブジェクトからキーを削除するにはどうすればよいですか?

分類Dev

JavaのArrayListからオブジェクトを削除するにはどうすればよいですか?

分類Dev

javaScriptオブジェクトから値を削除するにはどうすればよいですか?

分類Dev

オブジェクトの配列から値を削除するにはどうすればよいですか?

分類Dev

ArrayListからオブジェクトを正しく削除するにはどうすればよいですか?

分類Dev

範囲オブジェクトから#N / Aを削除するにはどうすればよいですか?

分類Dev

angleJsモデルからオブジェクトを削除するにはどうすればよいですか?

分類Dev

javascriptのオブジェクトから時間を削除するにはどうすればよいですか?

分類Dev

解析から特定のオブジェクトを削除するにはどうすればよいですか?

分類Dev

djangoで別のオブジェクトからオブジェクトを削除するにはどうすればよいですか?-python

分類Dev

JavaScriptを使用してオブジェクトの配列からオブジェクトを削除するにはどうすればよいですか?

分類Dev

基本オブジェクト配列の子オブジェクトからデータを取得するにはどうすればよいですか?

分類Dev

オブジェクト配列からオブジェクトを削除するにはどうすればよいですか?

分類Dev

Hibernateを使用して子オブジェクトを親クラスオブジェクトに保存するにはどうすればよいですか?

分類Dev

オブジェクトの配列から重複する子の値を削除するにはどうすればよいですか

分類Dev

このクラスオブジェクトを削除するにはどうすればよいですか?(C ++)

分類Dev

parse.comで古いオブジェクトを削除するにはどうすればよいですか

分類Dev

子オブジェクトの位置を1つに固定するにはどうすればよいですか?

分類Dev

ruby Tempfileオブジェクトに拡張子を追加するにはどうすればよいですか?

分類Dev

CSS divの子オブジェクトを中央に表示するにはどうすればよいですか?

分類Dev

jQuery.mapを使用してネストされたオブジェクトを再帰的に変更するにはどうすればよいですか

分類Dev

PHPの親オブジェクトを子オブジェクトに変換/キャストするにはどうすればよいですか?

分類Dev

Pythonオブジェクトを強制的に削除するにはどうすればよいですか?

分類Dev

単一のオブジェクトを返すときに、Array.prototype.find()を再帰的に使用するにはどうすればよいですか?

Related 関連記事

  1. 1

    PHPオブジェクトからJSONへ:複数の再帰的な子を持つクラスを作成するにはどうすればよいですか?

  2. 2

    オブジェクトをオブジェクトから別のオブジェクトに送信するにはどうすればよいですか?

  3. 3

    Djangoでオブジェクトを削除から保護するにはどうすればよいですか?

  4. 4

    jqを使用してサブオブジェクトをjsonオブジェクトから削除するにはどうすればよいですか?

  5. 5

    Javaの配列からオブジェクトを削除するにはどうすればよいですか?

  6. 6

    JavaScriptオブジェクトからキーを削除するにはどうすればよいですか?

  7. 7

    JavaのArrayListからオブジェクトを削除するにはどうすればよいですか?

  8. 8

    javaScriptオブジェクトから値を削除するにはどうすればよいですか?

  9. 9

    オブジェクトの配列から値を削除するにはどうすればよいですか?

  10. 10

    ArrayListからオブジェクトを正しく削除するにはどうすればよいですか?

  11. 11

    範囲オブジェクトから#N / Aを削除するにはどうすればよいですか?

  12. 12

    angleJsモデルからオブジェクトを削除するにはどうすればよいですか?

  13. 13

    javascriptのオブジェクトから時間を削除するにはどうすればよいですか?

  14. 14

    解析から特定のオブジェクトを削除するにはどうすればよいですか?

  15. 15

    djangoで別のオブジェクトからオブジェクトを削除するにはどうすればよいですか?-python

  16. 16

    JavaScriptを使用してオブジェクトの配列からオブジェクトを削除するにはどうすればよいですか?

  17. 17

    基本オブジェクト配列の子オブジェクトからデータを取得するにはどうすればよいですか?

  18. 18

    オブジェクト配列からオブジェクトを削除するにはどうすればよいですか?

  19. 19

    Hibernateを使用して子オブジェクトを親クラスオブジェクトに保存するにはどうすればよいですか?

  20. 20

    オブジェクトの配列から重複する子の値を削除するにはどうすればよいですか

  21. 21

    このクラスオブジェクトを削除するにはどうすればよいですか?(C ++)

  22. 22

    parse.comで古いオブジェクトを削除するにはどうすればよいですか

  23. 23

    子オブジェクトの位置を1つに固定するにはどうすればよいですか?

  24. 24

    ruby Tempfileオブジェクトに拡張子を追加するにはどうすればよいですか?

  25. 25

    CSS divの子オブジェクトを中央に表示するにはどうすればよいですか?

  26. 26

    jQuery.mapを使用してネストされたオブジェクトを再帰的に変更するにはどうすればよいですか

  27. 27

    PHPの親オブジェクトを子オブジェクトに変換/キャストするにはどうすればよいですか?

  28. 28

    Pythonオブジェクトを強制的に削除するにはどうすればよいですか?

  29. 29

    単一のオブジェクトを返すときに、Array.prototype.find()を再帰的に使用するにはどうすればよいですか?

ホットタグ

アーカイブ