Examples
Case 11: GitHub Repo Comparison (Async)

📈 GitHub Repository Comparison with Async Formulas

This demo showcases async formula functions in GridSheet by fetching live repository data from the GitHub API.

It compares popular frontend frameworks and runtimes — React, Vue, and Svelte — displaying stars, forks, open issues, language, license, and last updated date side by side.

Each cell containing a GH_REPO formula fetches data asynchronously and shows a loading animation while the request is in flight. The bottom row uses SUM to total stars, forks, and issues — it stays pending until all async cells resolve.

Debugger (inspect async evaluation & caching)
Registry State
1{}
Cell:
No cell data
System:
No system data
Formula Expressions
No cell selected
No sheets detected
Sheet Data
Sheet instance not found
Store Data
Store state not found

💡 Data is fetched live from the GitHub API with 1-minute caching. GH_REPO(repo) makes one API call per row and spills [[stars, forks, issues, size, subscribers]] across columns B–F automatically — 3 calls total instead of 18. Try editing a repository name in column A to fetch data for a different repo. The bottom row uses SUM to total all columns — it stays pending until all async cells resolve.

Implementation Guide

📄 View Source Code

Async Formula Functions with BaseFunctionAsync

Extend BaseFunctionAsync (instead of BaseFunction) to define a formula whose main method returns a Promise. GridSheet automatically handles the pending state and re-renders each cell when the promise resolves.

import { BaseFunctionAsync } from '@gridsheet/react-core';
 
class GhRepoFunction extends BaseFunctionAsync {
  example = 'GH_REPO("facebook/react")';
  ttlMilliseconds = 60 * 1000; // cache result for 1 minute
  defs = [{ name: 'repo', description: '"owner/repo" format', acceptedTypes: ['string'] }];
 
  async main(repo: string) {
    const resp = await fetch(`https://api.github.com/repos/${encodeURI(repo.trim())}`, {
      headers: { Accept: 'application/vnd.github.v3+json' },
      cache: 'force-cache',
    });
    const data = await resp.json();
    return new Spilling([[data.stargazers_count, data.forks_count, data.open_issues, data.size, data.subscribers_count]]);
  }
}

Register it via additionalFunctions in useSpellbook. The formula name is the key uppercased: =GH_REPO(A1).

Spilling Results Across Multiple Columns

Spilling wraps a 2D array and causes the result to overflow into adjacent cells automatically. Returning new Spilling([[v1, v2, v3]]) from a single formula call fills that cell and the next N−1 cells to the right.

return new Spilling([
  [data.stargazers_count, data.forks_count, data.open_issues, data.size, data.subscribers_count],
]);

In this demo, placing =GH_REPO(A1) in cell B1 spills Stars, Forks, Issues, Size, and Subscribers into B1:F1 with a single API call — 5 values per row, 3 repos, 3 API calls total instead of 15.

Pending State Propagation

When an async cell is still resolving, GridSheet marks it as Pending. Any formula that depends on a Pending cell (e.g., =SUM(B1:B3)) automatically waits and displays the loading animation until all upstream cells settle.

In this demo, the Total row uses =SUM(B1:B3) for each column. It stays pending until all three GH_REPO calls complete.

Built-in Result Caching via ttlMilliseconds

Set ttlMilliseconds on the function class to enable automatic result caching. The same arguments will return the cached result without making a new network request until the TTL expires.

ttlMilliseconds = 60 * 1000; // cache for 60 seconds

This prevents redundant API calls when a formula is re-evaluated due to an unrelated cell change.

Making Cells Editable to Trigger Re-fetches

Because the repo slug in column A is a plain string value, the user can edit it directly in the grid. When the value changes, =GH_REPO(A1) is invalidated and re-evaluated, fetching data for the new repository.

// In initialCells:
A1: { value: 'facebook/react', policy: 'repo' },
// Column B formula:
'=GH_REPO(A1)'  // re-runs whenever A1 changes

The Debugger Component

@gridsheet/react-dev exports a Debugger component that visualizes the current book state — pending cells, resolved values, and formula dependency graphs. It is useful during development to inspect async resolution.

import { Debugger } from '@gridsheet/react-dev';
 
<GridSheet book={book} ... />
<Debugger book={book} />