Wondering what’s next for npm?Check out our public roadmap! »

    @aduh95/async-jsx
    TypeScript icon, indicating that this package has built-in type declarations

    0.2.0 • Public • Published

    Async-JSX

    This package aims to give you the opportunity to use the JSX syntax introduced by React, without using React at all.

    Key differrences with React API:

    • No VirtualDOM (less overhead, but also less reactivity)
    • Everything is asynchronous
    • No Component life-cycle

    Usage

    Get Started

    import { h } from "@aduh95/async-jsx";
     
    const element = <div>Hello World</div>;
     
    console.log(element instanceof Promise); // true
     
    element.then(domElement => console.log(domElement instanceof HTMLElement)); // true
     
    document.body.append(renderAsync(element));

    It is recommanded to add this CSS to your page to avoid custom elements leaking into your design:

    async-component,
    conditional-element {
      display: contents;
    }
    dom-portal {
      display: none;
    }

    Build tools

    With Babel

    You can use the @babel/plugin-transform-react-jsx package:

    {
      "plugins": [
        [
          "@babel/plugin-transform-react-jsx",
          { "pragma": "h", "pragmaFrag": "Fragment" }
        ]
      ]
    }

    With TypeScript

    In the tsconfig.json:

    {
      "compilerOptions": {
        "jsx": "react",
        "jsxFactory": "h"
      }
    }

    With dynamic imports

    You can define a component in a separate file and lazy-load it:

    /* Greetings.js */
    import { h } from "@aduh95/async-jsx";
     
    // You can use an arrow function instead of a class
    export default props => (
      <div className={props.className}>Hello {props.name}</div>
    );
    /* App.js */
    import {
      h,
      lazy,
      Component,
      Fragment,
      conditionalRendering,
    } from "@aduh95/async-jsx";
    const Greetings = lazy(() => import("./Greetings.js"));
     
    export default class App extends Component {
      stateObservers = new Set();
      greetingName = "";
     
      _handleNewName = this.handleNewName.bind(this);
     
      handleNewName(ev) {
        const { target } = ev;
        this.greetingName = target.value;
        this.stateObservers.forEach(fn => fn("ready"));
      }
     
      render() {
        return (
          <>
            <h1>Welcome</h1>
            {conidtionalRendering(
              {
                ready: <Greetings name={this.greetingName} />,
                askForName: (
                  <input
                    autofocus
                    onBlur={this._handleNewName}
                    placeholder="What's your name"
                  />
                ),
              },
              this.stateObservers,
              ready,
              console.error
            )}
          </>
        );
      }
    }

    StatfulComponent

    I have added a React-compatible StatefulComponent, which can be used the same way as a React.Component. However, because of the lack of VirtualDOM, it can be highly inneficient to use it. For example, let's take the Clocl example from React docs:

    import { h, StatefulComponent } from "@aduh95/async-jsx";
    class Clock extends StatefulComponent {
      constructor(props) {
        super(props);
        this.state = { date: new Date() };
      }
     
      componentDidMount() {
        this.timerID = setInterval(() => this.tick(), 1000);
      }
     
      componentWillUnmount() {
        clearInterval(this.timerID);
      }
     
      tick() {
        this.setState({
          date: new Date(),
        });
      }
     
      render() {
        return (
          <div>
            <h1>Hello, world!</h1>
            <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
          </div>
        );
      }
    }
     
    document
      .getElementById("root")
      .append(renderAsync(<Clock />, null, console.error));

    This will work apparently, but at each tick, 3 DOM elements are initiated. Perf difference may not be visible on that small example, but you can imagine that having a whole site re-render everytime something change will put a lot of pressure on small-CPU clients.

    SVG Elements

    Because SVG Elements cannot be created using Document.prototype.createElement, but by Document.prototype.createElementNS, they cannot be created by the usual h p(or createElement) function. pIf you want to create SVG elements using JSX, you can put them in a separate module:

    // Logo.js
    import { createSVGElement as h } from "../utils/jsx.js";
     
    export default () => (
      <svg>
        <path />
      </svg>
    );

    Then you can import this module in another component:

    import { Component, h } from "../utils/jsx.js";
    import Logo from "./Logo.js";
     
    export default class Header extends Component {
      render() {
        return (
          <header>
            <Logo />
            <h1>Title</h1>
          </header>
        );
      }
    }

    API

    This repo is using TypeScript, you can use it to have access to the documentation during development. The API is defined by the .d.ts files.

    Install

    npm i @aduh95/async-jsx

    DownloadsWeekly Downloads

    0

    Version

    0.2.0

    License

    MIT

    Unpacked Size

    63.8 kB

    Total Files

    75

    Last publish

    Collaborators

    • avatar