Help

Re: Error: Rendered more/fewer hooks workarounds // combine queries

Solved
Jump to Solution
1170 0
cancel
Showing results for 
Search instead for 
Did you mean: 

I’m building a block which (should) allow users to select multiple records in Table A. I would like to get a set of each selected record’s linked Table B records. The problem I’m running in to I believe relates to using a hook within a loop.

Right now I’m using selectedRecords.map(record => {...} ).flat() to loop through each selected record. Within the loop, I’m using useRecords(record.selectLinkedRecordsFromCell(fieldName)) to get the linked records into a single array. This works but only if the user selects the same number of records each time, or cancels the current selection and starts over. Meaning if someone selects one record it works, if someone selects all records it works, but if someone changes the number of selected records by clicking and dragging or by using the selection boxes at the far left, React throws an error: Error: Rendered more/fewer hooks than during the previous render.

I think I could possible get around this if I could combine/collapse multiple record query results into one, then I’d only have to use useRecords() in one place and it could be a top level step. Is this possible? If not, is there some other workaround to get past this issue?

1 Solution

Accepted Solutions
somehats
6 - Interface Innovator
6 - Interface Innovator

Hi Kamille!

Under the hood, all that useRecords does is something like this:

useLoadable(query);
useWatchable(query, ['records', 'cellValues', 'recordColors']);
return query.records;

(it’s actually a little more complicated than that, but that’s the essence of it - you can check out the source code here if you’re interested!)

Whilst useRecords only accepts a single query/table/view etc, the lower-level useLoadable and useWatchable hooks accept arrays. That means you could do something like this:

// get linked record queries for every record:
const linkedRecordQueries = selectedRecords.map(
    record => record.selectLinkedRecordsFromCell(fieldName),
);

// load all the linked record queries:
useLoadable(linkedRecordQueries);
// rerender whenever any of the records in those queries change:
useWatchable(linkedRecordQueries, ['records', 'cellValues', 'recordColors']);

// get one big array with all the linked records:
const allLinkedRecords = linkedRecordQueries
    .map(query => query.records)
    .flat();

Creating lots of query results very dynamically like this though probably won’t be great for performance on large tables though.

Relevant docs links:

Hope this helps!

See Solution in Thread

2 Replies 2
somehats
6 - Interface Innovator
6 - Interface Innovator

Hi Kamille!

Under the hood, all that useRecords does is something like this:

useLoadable(query);
useWatchable(query, ['records', 'cellValues', 'recordColors']);
return query.records;

(it’s actually a little more complicated than that, but that’s the essence of it - you can check out the source code here if you’re interested!)

Whilst useRecords only accepts a single query/table/view etc, the lower-level useLoadable and useWatchable hooks accept arrays. That means you could do something like this:

// get linked record queries for every record:
const linkedRecordQueries = selectedRecords.map(
    record => record.selectLinkedRecordsFromCell(fieldName),
);

// load all the linked record queries:
useLoadable(linkedRecordQueries);
// rerender whenever any of the records in those queries change:
useWatchable(linkedRecordQueries, ['records', 'cellValues', 'recordColors']);

// get one big array with all the linked records:
const allLinkedRecords = linkedRecordQueries
    .map(query => query.records)
    .flat();

Creating lots of query results very dynamically like this though probably won’t be great for performance on large tables though.

Relevant docs links:

Hope this helps!

Thank you!! for both the quick response and the warning of performance.