Jun 23, 2020 10:22 PM
I have added a form field to my custom block and I am updating its value via the React state. It works well and looks fast.
The block is fairly standard. It reads values from a table, filters them and then displays them in a list.
When I look at the console I see my logs telling how many rows were read after every character entered into the input field.This means all the code of my block (inside index.js) is executed again and again. There is a useRecords statement just before this log output.
Does this mean the rows are read from Airtable for every character pressed (round trip every time)? Or is there some form of caching?
Will I get a performance hit when there are many (1000+) rows in the table?
Jun 25, 2020 01:13 AM
Hi Chris,
The rows are not read on each keypress. Updating the input updates state, which causes the block to re-render. The component’s code is executed on each render as it’s a React function component, so that’s expected.
I can’t say for sure without seeing the code, but my guess is that your logging is occurring on each render. If it’s something like const records = useRecords(table); console.log(records.length)
, this is showing how many records there are on each render, not that that many records were just loaded.
Billy’s response about when new renders occur provides more details: AMA Custom Blocks Contest Edition #3 - Releasing your block - #29 by Billy_Littlefield
Regarding record data loading: the SDK handles loading the data on demand (e.g. component using useRecords
is mounted), listening to updates coming from Airtable + notifying you of updates, and unloading it when no longer required (e.g. the component using useRecords
unmounts). Since it’s loading all of this data and holding it in memory, performance will degrade if there are lots of records and/or fields. To address this, we recommend using RecordQueryResultOpts
to only load the data for the fields you need.
Jun 25, 2020 09:24 PM
OK So here is how I understand it: The actual reading of the records happens in the React component which mirrors somehow an Airtable “middleware” object that gives me the data (all rows for the table) and updates the state of the data as needed so that the React object can re-render and show me the updated data. I can specify a sub-set of columns but not of rows, so I always get all rows.
So this leads me to another question. How much data is actually brought “down the wire” and when? If I look at Airtable, there is one tab per table and all the rows of a table showing on a tab. If a table has links to say 5 other tables, is the all the data of those other five tables coming into the React component? How does Airtable then handle large datasets. Let us say I have a list of 5000 materials and I have a works order table that can use any one of those materials, are all 5000 materials also loaded?
In the api model there is the concept of a cursor and one actually pulls just the rows and columns one needs, 100 at a time. But it looks to me like that is not the case with custom blocks.
Jun 29, 2020 01:09 AM
Hi Chris,
Will respond to your message in parts as there’s a lot to unpack here!
OK So here is how I understand it: The actual reading of the records happens in the React component which mirrors somehow an Airtable “middleware” object that gives me the data (all rows for the table) and updates the state of the data as needed so that the React object can re-render and show me the updated data.
Essentially, yes. To go into specifics, what useRecords
does under the hood is:
QueryResult
for the table/viewQueryResult
using useLoadable
.
queryResult.loadDataAsync()
and put the block into React suspense (shows a loading spinner) while the data is loading asynchronouslyQueryResult
using useWatchable
You can see more details in the source code for useRecords
and in the guide about reading data in a custom block. useLoadable
, useWatchable
and queryResult
can all be used directly, but we generally recommend using the higher level hooks as they’re easier to use.
I can specify a sub-set of columns but not of rows, so I always get all rows.
This is correct
So this leads me to another question. How much data is actually brought “down the wire” and when?
It depends what you mean by “the wire”. Blocks run in the context of an Airtable base, where the table data is actually already loaded into your browser. When we say the data is asynchronously being loaded into the block, that means it’s being loaded from the main Airtable window into the block’s iframe.
If I look at Airtable, there is one tab per table and all the rows of a table showing on a tab. If a table has links to say 5 other tables, is the all the data of those other five tables coming into the React component? How does Airtable then handle large datasets. Let us say I have a list of 5000 materials and I have a works order table that can use any one of those materials, are all 5000 materials also loaded?
When using linked records, you need to load the data of the linked records separately by getting the LinkedRecordsQueryResult
from record.selectLinkedRecordsFromCell
and loading it.
(So, to answer your question more directly: if you’re only doing useRecords(mainTable)
or similar, that only loads/watches mainTable
and not the linked tables. You can see what’s loaded for the linked record cells by referring to the cell read format here - it’s just the name and id.)
In the api model there is the concept of a cursor and one actually pulls just the rows and columns one needs, 100 at a time. But it looks to me like that is not the case with custom blocks.
That’s correct, there is no pagination within the current custom blocks APIs.
Hope that helps!
Jun 29, 2020 01:41 AM
Thank you for a thorough reponse.