javascript 50 lines · 9 steps

Building a reactive spreadsheet engine

A minimal spreadsheet that tracks cell dependencies automatically and recomputes downstream cells when a formula changes.

Explained by highlit
1class Sheet {
2 constructor() {
3 this.cells = new Map();
4 this.computing = new Set();
5 }
6 
7 set(name, definition) {
8 const cell = this.cells.get(name) || this._create(name);
9 cell.deps.forEach((dep) => this.cells.get(dep)?.dependents.delete(name));
10 cell.deps = new Set();
11 cell.formula = typeof definition === 'function' ? definition : () => definition;
12 this._recompute(name);
13 }
14 
15 get(name) {
16 const reader = this._activeReader;
17 if (reader) {
18 this.cells.get(reader).deps.add(name);
19 this._create(name).dependents.add(reader);
20 }
21 return this._create(name).value;
22 }
23 
24 _create(name) {
25 if (!this.cells.has(name)) {
26 this.cells.set(name, { value: undefined, formula: () => undefined, deps: new Set(), dependents: new Set() });
27 }
28 return this.cells.get(name);
29 }
30 
31 _recompute(name) {
32 if (this.computing.has(name)) {
33 throw new Error(`Circular reference detected at ${name}`);
34 }
35 this.computing.add(name);
36 const cell = this.cells.get(name);
37 const prevReader = this._activeReader;
38 this._activeReader = name;
39 try {
40 cell.value = cell.formula((ref) => this.get(ref));
41 } finally {
42 this._activeReader = prevReader;
43 this.computing.delete(name);
44 }
45 for (const dependent of cell.dependents) {
46 this._recompute(dependent);
47 }
48 return cell.value;
49 }
50}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Dependency edges can be discovered automatically by recording which cells are read during a formula's evaluation.
  2. 2Tracking a currently-computing set turns infinite recursion from circular formulas into a clean, catchable error.
  3. 3Recomputing a cell's dependents recursively propagates a single change through the entire graph.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Building a reactive spreadsheet engine — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code