Multiple useRecords hooks causing repeated restarts in custom Airtable block app

I’m building a custom Airtable block app that pulls data from several tables. The app shows this info in context and connected. I’m using useRecords hooks to keep things updated when users make changes. But now the app is super slow to load. It keeps restarting with each useRecords hook. Is there a trick to fix this while still getting all the table data I need?

Here’s a simplified version of what I’m doing:

import { useBase, useRecords } from '@airtable/blocks/ui';
import React from 'react';

function MyCustomApp() {
  const base = useBase();
  const tableNames = ['Products', 'Expenses', 'Clients', 'Sales', 'Team'];
  
  const tables = React.useMemo(() => {
    return tableNames.reduce((acc, name) => {
      acc[name.toLowerCase()] = base.getTableByNameIfExists(name);
      return acc;
    }, {});
  }, [base]);

  console.log('Connected to tables');

  const data = {};
  for (const [key, table] of Object.entries(tables)) {
    data[key] = useRecords(table);
    console.log(`Loaded ${key} data`);
  }

  // Rest of the app logic
}

The console shows it’s restarting for each table. Any ideas on how to make this more efficient?

hey tom, i ran into similar issues. try using a custom hook to batch ur useRecords calls. something like:

const useMultipleRecords = (tables) => {
  return Object.entries(tables).reduce((acc, [key, table]) => {
    acc[key] = useRecords(table);
    return acc;
  }, {});
};

ten just call it once w/ ur tables object. should cut down on rerenders big time!

I’ve encountered this issue before in my Airtable projects. The problem lies in how React handles multiple state updates. A more efficient approach is to use a single useRecords call with a query that joins the necessary tables. This reduces the number of hooks and prevents excessive re-renders.

Here’s a rough example of how you might restructure your code:

const tableQuery = base.tables.filter(table => tableNames.includes(table.name));
const allRecords = useRecords(tableQuery);

const data = React.useMemo(() => {
  return allRecords.reduce((acc, record) => {
    const tableName = record.parentTable.name.toLowerCase();
    if (!acc[tableName]) acc[tableName] = [];
    acc[tableName].push(record);
    return acc;
  }, {});
}, [allRecords]);

This approach should significantly improve your app’s performance while still keeping your data up-to-date.

I feel your pain, Tom. I’ve been there with complex Airtable apps. One approach that worked wonders for me was using a reducer pattern with useReducer and context. It centralizes state management and minimizes re-renders.

Here’s a basic idea:

  1. Create a context for your app state
  2. Set up a reducer to handle all data updates
  3. Wrap your app in a provider that uses useReducer
  4. Use useEffect to fetch data for each table once
  5. Dispatch actions to update state as needed

This way, you’re only calling useRecords once per table, and React handles state updates more efficiently. It took some refactoring, but my app’s performance improved dramatically. Plus, it made the code more maintainable in the long run.

Just remember to memoize expensive computations and use callbacks wisely to prevent unnecessary re-renders. Good luck with your project!