I’m trying to make a table like this:
| -------- | - <Tr> | + <Tr> | - <Tr> | - <Tr> | - <Tr> | <Tr> | <Tr> | <Tr> | + <Tr> | + <Tr>
Table elements can contain thousands of child dropdown elements.
I am writing code in React and so far I have no idea and have not figured out how it can be done in a more optimized way.
Right now I am trying to work with a data structure like this
[ { id: 1, childrens: [ { id: 10, childrens: [] }, { id: 11, childrens: [{ id: 12, childrens: [] }] }, ], }, { id: 2, childrens: [] }, ];
Current implementation idea:
When I click on the dropdown element, I do the following:
- Get id
- I am looking for an element in the array by id
- I get the contents of
childrens
, if the array contains data, then I add them after the parent<tr>
element
To hide the dropdown <tr>
I do the following:
- Get id
- I am looking for an element in the array by id
- Get the length of the array
childrens
- I delete after the parent
<tr
element, the number of child<tr
is equal to the length of the array
But I don’t understand how I can work with nested child elements. I need to somehow understand who is the parent of whom in order not to bypass the entire array again.
In what direction should I explore this issue?
Advertisement
Answer
I had to do this once and solved it using recursion. Create your table and loop over the first layer of data.
const TableDropdown = ({ data }) => { return ( <table> <tbody> // loop over the first layer of data {data.map((row) => ( <DropdownRow key={`dropdown-row-${row.id}`} row={row} /> ))} </tbody> </table> ); };
For the implementation of the row
- In the row we set a state to keep track of the open state.
- Define a toggle function to toggle between open and closed.
- Finally determine whether or not we have children and check if the dropdown is open.
const DropdownRow = ({ row }) => { const [isOpen, setIsOpen] = useState(false); // check whether the row has children const hasChildren = row.childrens.length > 0; // toggle the row const toggleRow = () => { // no need to toggle if no children if (!hasChildren) return; setIsOpen((prev) => !prev); }; // create the child rows if the current row has children and is opened const childRows = hasChildren && isOpen ? row.childrens.map((childRow) => ( <DropdownRow key={`dropdown-row-${childRow.id}`} row={childRow} /> )) : null; // just to determine which "icon" to display const toggleIcon = !hasChildren ? "=" : isOpen ? "-" : "+"; return ( <> <tr> <td onClick={toggleRow}>{toggleIcon}</td> <td>Row with id {row.id}</td> </tr> {childRows} </> ); };
Check here for a live version