Skip to content
This repository has been archived by the owner on Dec 6, 2021. It is now read-only.

tvler/experimental-react-like-framework

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

36 Commits
 
 
 
 
 
 

Repository files navigation

experimental-react-like-framework

A new, experimental frontend for React inspired by SwiftUI. In development.

Based off of two questions:

① What would React look like if execution-order-based code wasn't used only for hooks, but for everything?

② What would React look like if JSX never existed?

Hello World app:

const App = () => {
  h1("Hello world!");
};

The framework is hosted on React itself. Designed to be incrementally adopted inside of a React subtree without interfering with any existing code, with the benefit of all of React's features and ecosystem.

import { NewFramework } from "./NewFramework";
import { NewFrameworkApp } from "./NewFrameworkApp";

const App = () => (
  <YourExistingReactApp>
    <YourExistingReactComponent />

    {/* 🆕 */}
    <NewFramework root={NewFrameworkApp} />
  </YourReactApp>
);

Table of contents

Framework write-up

Bet: JSX is bad

JSX immediately requires a complex build environment. Differences between HTML is small but painful for beginners. Sebastian Markbåge (a lead react maintainer) tweeted that JSX is a bug.

(twitter.com/sebmarkbage/status/1255886278437945344)

Bet: React.createElement is bad

Using React without JSX forces you to use the React.createElement API. Building a complex template with React.createElement ends up as a deeply-nested function call with no breakpoints at the very bottom of your component code. JSX is an attempt to make this format more presentable, but it doesn't solve the underlying issue that your template is inside of a function call, with no access to if-statements, for-loops, etc.

Bet: Code based off of execution-order is good

Facebook built hooks around execution-order and received major backlash by the engineering community, but resulted in few actual real-world problems.

Result

An exploration of what react would look like if execution-order-based code wasn’t considered an antipattern, and if JSX never existed.

/*
 * New syntax
 */
const App = () => {
  const [counter, setCounter] = useState(0);
  const handleClick = () => {
    setCounter(counter + 1);
  };

  h1("Hello world!");

  // A button with an onClick prop
  button({ onClick: handleClick }, counter);

  // An ordered list counting up from 0 to 9
  ol(() => {
    for (let i = 0; i < 10; i++) {
      li({ key: i }, i);
    }
  });

  // Conditionally rendering a span if counter is odd
  if (counter % 2) {
    span("counter is an odd number.");
  }
};

/*
 * Old JSX syntax
 */
const JSXApp = () => {
  const [counter, setCounter] = useState(0);
  const handleClick = () => {
    setCounter(counter + 1);
  };

  return (
    <>
      <h1>Hello world!</h1>

      {/* A button with an onClick prop */}
      <button onClick={handleClick}>{counter}</button>

      {/* An ordered list counting up from 0 to 9 */}
      <ol>
        {Array.from({ length: 10 }, (_, i) => (
          <li key={i}>{i}</li>
        ))}
      </ol>

      {/* Conditionally rendering a span if counter is odd */}
      {counter % 2 && <span>counter is an odd number.</span>}
    </>
  );
};

Benefits

Simpler code for loops and conditional rendering

Zero distinction between functions and components

Don’t have to learn JSX

No return statement

No need for closing tags

No need for fragments

Easier to comment elements out

How it works

Each primitive HTML element function pings a global store when called. The order of the pings determines the order in which the actual HTML elements are rendered to the dom. This is the exact same architecture that Facebook has proven successful with react hooks.

This has the potential to work directly within React itself, turning into a series of React.createElement calls on execution. Making this an experimental new frontend for React, with the added benefits of gradual adoption and an already-existing suite of developer tools to build off of.

What I've built so far

✅ Working prototype

cd example-create-react-app
yarn
yarn start

✅ Everything except state

example-create-react-app/src/app.ts

import { button, h1, ol, li } from "./Framework";

const app = () => {
  h1("Hello world!");

  // A button with an onClick prop
  button(
    {
      onClick: () => {
        alert("clicked!");
      },
    },
    "Click"
  );

  // An ordered list counting up from 0 to 9
  ol(() => {
    for (let i = 0; i < 10; i++) {
      li(i);
    }
  });
};

export default app;

✅ Building on top of React

example-create-react-app/src/index.ts

import React from "react";
import ReactDOM from "react-dom";
import { Framework } from "./Framework";
import app from "./app";

ReactDOM.render(
  React.createElement(Framework, { root: app }),
  document.getElementById("root")
);

What needs to be built

  • State
  • A cool project name ;) #4

Further reading

Function builders (draft proposal) by John McCall and Doug Gregor

js-dsl by Venkat Peri

incremental-dom by Google