2

I have been working with React Query and React Table recently to achieve a multi-level table structure with expandable rows, where each row should do lazy loading when clicked on. It's for product group hierarchy, which looks like this:

unit-1 (clicking fetches category data lazily)
  category-1 (clicking fetches product data lazily)
    product-1
    product-2
  category-2
    product-3
unit-2
  category-3
    product-4
    product-5

I have two options for the solution:

  • Sub components lazy load example for React Table (https://react-table.tanstack.com/docs/examples/sub-components-lazy) This focuses on only one level of depth, so I am not sure how to make it multi-level due to the fact that I am still not very familiar with the React Table API and it seems like the example was not created with that purpose. I tried making it multi-level but I had difficulty in passing some row properties around like (.isExpanded, .id, etc)

  • A post about manipulating the data by each row click so that rest is handled automatically by the table (https://nafeu.medium.com/lazy-loading-expandable-rows-with-react-table-cd2fc86b0630 - GitHub ex: https://github.com/nafeu/react-query-table-sandbox/blob/main/src/ReactTableExpanding.jsx) This seems to be a more declarative way to handle things. (We fetch new data, merge it with the existing data and the rest is handled) but I have some concerns like if updating the whole table data causes unnecessary renders. Another thing is since we don't render a sub-component here as in the first one, the API endpoint should be arranged to work with a click event. It's not like having a sub-component that is responsible for fetching its own data when it's mounted.

As a note for the table example above, I was planning to use a single API endpoint that takes params like:

?level=root&id=0 (initial units list data for the table on page load)
?level=unit&id=2 (returns categories of unit-2) 
...

But this logic doesn't seem enough for supporting fetching on row click so I guess I'll need at least two endpoints if I follow the second approach.

Thanks for reading, and any ideas are welcome! Have a nice day.

Orkun Tuzel
  • 1,342
  • 10
  • 22

1 Answers1

1

As an update, I could make things work mostly with the second option above. As a note on the API endpoints, I could use the same API endpoint and the same hook twice with different parameters. (this part is a bit project specific of course but maybe it gives an idea to the ones having similar scenarios)

To get the initial data for the table, I give hardcoded parameters to the hook, so that the table is rendered with the initialData on page load.

const { data: initialData, isLoading } = useGetLevels(
  {
    level: 'root',
    id: [0],
    ...
  }
 );

In the second one, I use enabled: false, and when a row is clicked on I call refetch(), so additional data is fetched and merged with the initial data to update the table and the row is expanded accordingly:

const {
  data: partialData,
  refetch,
} = useGetLevels(
  {
    level,
    id,
    ...
  },
  false
);

and the useGetLevels look like this:

function useGetLevels(
filterParams,
enabled
) {
return useQuery(
  ['levels', filterParams],
  () => fetchLevels(filterParams),
  {
    enabled,
  }
);
}
Orkun Tuzel
  • 1,342
  • 10
  • 22