Dan Zawadzki
Dan Zawadzki

Reputation: 732

Table inside other table row in ReactJS

I have to build something between tree and table. I have folder, subfolders and elements. There is one folder, which keeps inside all subfolders. Informations rendering correctly, but react is ignoring part of my code.

const Folder = (props) => {
    return (
        <tr key={props.id}>
            <td className='w1_20'><input type='checkbox'/></td>
            <td className='w1_10'>{props.id}</td>
            <td className='w5_10'><a href=''>{props.name}</a></td>
            <td className='w2_10'/>
            <td className='w3_20'/>
        </tr>
    )
};

This is my folder component.

const Subfolder = (props) => {
    return (
        <tr>
            <td className='p-0 bt-0' colSpan='5'>
                <table className='table table-hover w-100'>
                    <tbody>
                    {props.children}
                    </tbody>
                </table>
            </td>
        </tr>
    )
};

This is my subfolder component.

const Segment = (props) => {
    return (
        <tr key={props.element.id}>
            <td className='w1_20'><input type='checkbox'/></td>
            <td className='w1_10'>{props.element.id}</td>
            <td className='w5_10'>{props.element.name}</td>
            <td className='w2_10'>{props.element.value}</td>
            <td className='w3_20'/>
        </tr>
    )
};

This is element.

The structure should looks like:

Structure

Each subfolder should be next row after the folder row and it contains table inside (this is really important, as later I need to be able to manipulate these tables). Inside subfolders, can be element rows or another subfolder.

I know, that subfolders should have key also, but the major problem for me now is that React completely ignore, that inside subfolder td element I'm using another table with props children.

return (
    <tbody>
        <Folder id={1} name="Folder" />
        <Subfolder>
            <Subfolder>
                <Segment segment={{id: 1, name: "Element"}}/>
            </Subfolder>
        </Subfolder>
    </tbody>
);

If I try to use it this way, it works fine. But to parse my API response I have function, where I push each element inside array, which I return at the end.

const InitTable = (props) => {
    let table = [];

    const mapResponse = (data) => {
        if (data) {
            if (data['folder']) {
                table = [...table, <Folder key={data.folder.id} id={data.folder.id} name={data.folder.name}/>];

                let sf = data['children'].map((item) => {
                    if (item) {
                        return mapResponse(item);
                    }
                });

                table = [...table, <Subfolder>{sf}</Subfolder>];

            } else if (data['segment']) {
                if (data['statistics']) {
                    table = [...table, <Segment statistics={data['statistics']} segment={data['segment']}/>];
                }
            }
        }
    };

    if (props.segments) {
        mapResponse(props.segments.root);
    }

    return (
        <tbody>
        {table}
        </tbody>
    );
};

I need to create chunk of JSX and render at the end, so i check type of each object in the API response and push different component to the array. The main problem is that then, React completely ignore my tables inside td elements are render all as regular table.

enter image description here

When I'm expecting something more like:

enter image description here

I know the easiest way is to build it as normal string and later use dangerouslySetInnerHTML() method, but I want to avoid it.

Upvotes: 1

Views: 2814

Answers (1)

TryingToImprove
TryingToImprove

Reputation: 7407

It seems like there are 2 issues

  1. <Segment segment={{id: 1, name: "Element"}}/> takes a element prop, but your passing it a segment

  2. You method for creating the main tbody is adding to the same array instead of returning a new one.


const InitTable = props => {
  const mapResponse = data => {
    if (data) {
      if (data['folder']) {
        let sf = data['children'].map(item => {
          if (item) {
            return mapResponse(item);
          }
        });

        return [
          <Folder
            key={data.folder.id}
            id={data.folder.id}
            name={data.folder.name}
          />,
          <Subfolder>{sf}</Subfolder>,
        ];
      } else if (data['segment']) {
        if (data['statistics']) {
          return [
            <Segment
              statistics={data['statistics']}
              element={data['segment']}
            />,
          ];
        }
      }
    }
  };

  return (
    <tbody>
      {mapResponse(props.segments.root)}
    </tbody>
  );
};

https://codesandbox.io/s/gJJ2Lm2vD

Upvotes: 1

Related Questions