Help

Re: Multiple useRecords hooks to different tables force repeated app restarts

Solved
Jump to Solution
546 0
cancel
Showing results for 
Search instead for 
Did you mean: 
Michael_Schmidt
4 - Data Explorer
4 - Data Explorer

My app is reading data from multiple tables, then displays them in context and interconnected. To be able to react to user changes I’m using the useRecords hook, so that updates propagate to the app.

When searching why the app loads so slowly I realized that it starts over and over again, with each useRecords hook. Is there a way/pattern to avoid this, while still being able to read all the necessary table data?

My code:

...
const base = useBase();
  // get all necessary Airtable tables
  const tables = React.useMemo(() => {
    return {
      productTable: base.getTableByNameIfExists(Constants.PRODUCTS_TABLE_NAME),
      costTable: base.getTableByNameIfExists(Constants.COST_TABLE_NAME),
      contactsTable: base.getTableByNameIfExists(Constants.CONTACTS_TABLE_NAME),
      conversionTable: base.getTableByNameIfExists(Constants.CONVERSIONS_TABLE_NAME),
      contributorTable: base.getTableByNameIfExists(Constants.CONTRIBUTORS_TABLE_NAME),
    };
  }, [base]);
  console.log('tables have been connected...')

  const conversions = useRecords(tables.conversionTable);
  console.log('conversions data has been read...')
  const contributors = useRecords(tables.contributorTable);
  console.log('contributor data has been read...')
  const costs = useRecords(tables.costTable);
  console.log('tracker data has been read...')
  const products = useRecords(tables.productTable);
  console.log('product data has been read...')
  const vendors = useRecords(tables.contactsTable);
  console.log('vendor data has been read...')
...

Console Output:

tables have been connected...
...
tables have been connected...
conversions data has been read...
...
tables have been connected...
conversions data has been read...
contributor data has been read...
...
tables have been connected...
conversions data has been read...
contributor data has been read...
tracker data has been read...
...
tables have been connected...
conversions data has been read...
contributor data has been read...
tracker data has been read...
product data has been read...
...
tables have been connected...
conversions data has been read...
contributor data has been read...
tracker data has been read...
product data has been read...
vendor data has been read...
...
1 Solution

Accepted Solutions
Albrey_Bristo-B
6 - Interface Innovator
6 - Interface Innovator

Hi Michael,
As you point out, the useRecords() hook will update the component used by your app with the underlying data changes to records, but it also handles loading data automatically.

Within the useRecords() hook we use suspense while loading data so that downstream logic does not get called until the data has finished loading. As you see from your console output, this causes the component to be re-rendered with each call of useRecords() before the next line can be executed.

You might be able to reduce some of the slowness your app is experiencing by starting the data load outside of the useRecords() call which uses the suspended loads. loadDataAsync() will allow you to do this asynchronously for each table and can be called from a query result, such as the one returned by table.selectRecords(). That way, the data for each table starts loading before suspense is used via useRecords().

You’ll still see the component re-render once the data for each is finished loading, but since the loading will now happen asynchronously, this should cut out some of the overall load time. Here’s what that might look like:

const base = useBase();
  // get all necessary Airtable tables
  const tables = React.useMemo(() => {
    return {
      productTable: base.getTableByNameIfExists(Constants.PRODUCTS_TABLE_NAME),
      costTable: base.getTableByNameIfExists(Constants.COST_TABLE_NAME),
      contactsTable: base.getTableByNameIfExists(Constants.CONTACTS_TABLE_NAME),
      conversionTable: base.getTableByNameIfExists(Constants.CONVERSIONS_TABLE_NAME),
      contributorTable: base.getTableByNameIfExists(Constants.CONTRIBUTORS_TABLE_NAME),
    };
  }, [base]);
    console.log('tables have been connected...')

    const productTableQueryResult = tables.productTable.selectRecords()
    const costTableQueryResult = tables.costTable.selectRecords()
    const contactsTableQueryResult = tables.contactsTable.selectRecords()
    const conversionTableQueryResult = tables.conversionTable.selectRecords()
    const contributorTableQueryResult = tables.contributorTable.selectRecords()
    
    React.useEffect( () => {
        productTableQueryResult.loadDataAsync()
        costTableQueryResult.loadDataAsync()
        contactsTableQueryResult.loadDataAsync()
        conversionTableQueryResult.loadDataAsync()
        contributorTableQueryResult.loadDataAsync()

        return () => {
            productTableQueryResult.unloadData()
            costTableQueryResult.unloadData()
            contactsTableQueryResult.unloadData()
            conversionTableQueryResult.loadDataAsync()
            contributorTableQueryResult.loadDataAsync()
        }
    }, [])

  const conversions = useRecords(tables.conversionTable);
  console.log('conversions data has been read...')
  const contributors = useRecords(tables.contributorTable);
  console.log('contributor data has been read...')
  const costs = useRecords(tables.costTable);
  console.log('tracker data has been read...')
  const products = useRecords(tables.productTable);
  console.log('product data has been read...')
  const vendors = useRecords(tables.contactsTable);
  console.log('vendor data has been read...')

Let us know if that works for you.

See Solution in Thread

3 Replies 3
Michael_Schmidt
4 - Data Explorer
4 - Data Explorer

It seems as if nobody has encountered (or esolved) this before? A cross-posting at Stackoverflow has not yielded any insights either.

Albrey_Bristo-B
6 - Interface Innovator
6 - Interface Innovator

Hi Michael,
As you point out, the useRecords() hook will update the component used by your app with the underlying data changes to records, but it also handles loading data automatically.

Within the useRecords() hook we use suspense while loading data so that downstream logic does not get called until the data has finished loading. As you see from your console output, this causes the component to be re-rendered with each call of useRecords() before the next line can be executed.

You might be able to reduce some of the slowness your app is experiencing by starting the data load outside of the useRecords() call which uses the suspended loads. loadDataAsync() will allow you to do this asynchronously for each table and can be called from a query result, such as the one returned by table.selectRecords(). That way, the data for each table starts loading before suspense is used via useRecords().

You’ll still see the component re-render once the data for each is finished loading, but since the loading will now happen asynchronously, this should cut out some of the overall load time. Here’s what that might look like:

const base = useBase();
  // get all necessary Airtable tables
  const tables = React.useMemo(() => {
    return {
      productTable: base.getTableByNameIfExists(Constants.PRODUCTS_TABLE_NAME),
      costTable: base.getTableByNameIfExists(Constants.COST_TABLE_NAME),
      contactsTable: base.getTableByNameIfExists(Constants.CONTACTS_TABLE_NAME),
      conversionTable: base.getTableByNameIfExists(Constants.CONVERSIONS_TABLE_NAME),
      contributorTable: base.getTableByNameIfExists(Constants.CONTRIBUTORS_TABLE_NAME),
    };
  }, [base]);
    console.log('tables have been connected...')

    const productTableQueryResult = tables.productTable.selectRecords()
    const costTableQueryResult = tables.costTable.selectRecords()
    const contactsTableQueryResult = tables.contactsTable.selectRecords()
    const conversionTableQueryResult = tables.conversionTable.selectRecords()
    const contributorTableQueryResult = tables.contributorTable.selectRecords()
    
    React.useEffect( () => {
        productTableQueryResult.loadDataAsync()
        costTableQueryResult.loadDataAsync()
        contactsTableQueryResult.loadDataAsync()
        conversionTableQueryResult.loadDataAsync()
        contributorTableQueryResult.loadDataAsync()

        return () => {
            productTableQueryResult.unloadData()
            costTableQueryResult.unloadData()
            contactsTableQueryResult.unloadData()
            conversionTableQueryResult.loadDataAsync()
            contributorTableQueryResult.loadDataAsync()
        }
    }, [])

  const conversions = useRecords(tables.conversionTable);
  console.log('conversions data has been read...')
  const contributors = useRecords(tables.contributorTable);
  console.log('contributor data has been read...')
  const costs = useRecords(tables.costTable);
  console.log('tracker data has been read...')
  const products = useRecords(tables.productTable);
  console.log('product data has been read...')
  const vendors = useRecords(tables.contactsTable);
  console.log('vendor data has been read...')

Let us know if that works for you.

Thanks a lot, will give this a try!