fe-fwk-ts-react

Render is cheap. The DOM is not.

A notes app built with a TypeScript port of the framework from the book Build a Frontend Web Framework (From Scratch), with React’s names. Move the slider through seven edits of a notes list and see two numbers for each: how many components ran render(), and how many times the page’s DOM really changed.

Demo

Legend: render() ran: the component computed its next tree DOM write: the browser changed the page table: changed in this step, old value struck through

render() 0 · DOM writes 0

Each position · props, state and the native input
Real DOM · what’s on the page, classes hidden

What to notice

Render is a calculation

render() returns the component’s next tree of plain objects. A console.log in it prints every time, but the page changes only where the new tree differs from the old one. App renders on every step, and most of what it returns is already on the page.

Most lists don’t need keys

Editing a note, adding to the end, removing the last: turn keys off and steps 2 to 4 give the same page and the same DOM writes. Without keys, a child is matched by its position, and these edits keep positions.

Without keys, state stays put

Add to the top without keys and the page still reads right: every position gets new props, one <li> is added at the end. But the table shows that state and the typed text didn’t move. The framework is right by its own rules: same position, same component.

One difference from React: here a component whose props didn’t change skips render(), which is what React.memo does. Plain React calls every child of a component that renders. The DOM writes are the same.

Run it

Requires Node.js 22 or newer. The runtime isn’t published to npm: it’s a learning project, so you clone it.

  1. 1

    Clone and install

    git clone https://github.com/slimcandy/fe-fwk-ts-react
    cd fe-fwk-ts-react
    npm install
  2. 2

    Test it, open this demo

    npm test      # the book's tests and the React comparison
    npm run dev   # this page, at http://localhost:5173
  3. 3

    Write a component

    import {
      createApp,
      createComponent,
      createElement,
    } from "fe-fwk-ts-react";
    
    const Counter = createComponent({
      state() {
        return { count: 0 };
      },
      render() {
        const { count } = this.state;
        return createElement(
          "button",
          { on: { click: () => this.setState({ count: count + 1 }) } },
          [`Clicked ${count} times`]
        );
      },
    });
    
    createApp(Counter).mount(document.body);