Giter Club home page Giter Club logo

reactive's Introduction

@pago/reactive

Introduction | API Docs | CodeSandbox | Next.js Example | Examples

You are using React or Preact but find yourself frustrated by continuous bugs, errors or ceremony caused by the Hooks API? You thought you could avoid using a separate state management library like Redux, Recoil or MobX but started to run into unexpected performance issues with the Context API?

Then this library will eventually be the one for you! A reactive component model on top of React and Preact with automatic performance optimizations and a simple and predictable API that gets out of your way and supports you in achieving your goals. Blatantly copied from the fantastic Vue Composition API. But for React / Preact.

Huh? Eventually? Oh yes, this thing is bleeding cutting edge and likely to cause you all kinds of pain right now. Please don't use this in production. We are looking for feedback and observations from experiments you run. We fully expect to change major parts of the API in various different ways while we try to find the right set of primitives and abstractions to have a good balance between power and ease of learning.

If you would like to play around with the library:

Project Plan

We are roughly following planning to go through the following steps:

  • Make it work
  • Make it good (<-- we are here)
  • Stable release
  • Make it fast
  • Make it small

Current State of the Project

  • Works with Preact & React
  • Very little boilerplate on top of React (JS: none, TS: minimal r)
  • Observable values
  • Efficient derived values
  • Works with Suspense
  • Works with React.Context (through inject)
  • Concurrent Mode Safe (!) (as far as I can see, Expert review would be great)
  • Reuse your existing Hooks in a Reactive Component through fromHook
  • Reuse ref values in Hooks components through useRefValue
  • Doesn't show any wrapper components in React DevTools
  • Perfect for incremental adoption into existing projects (use the pragma comment for per-file adoption)
  • TypeScript: Do we really need r? Can we adapt the JSX.Element['type'] property to include our kind of components?
  • Lifecycle callbacks (do we really need them? All can be replicated in user-land if needed)
  • Rx.js interop? Useful? How do we handle subscriptions?
  • Optimized Preact implementation (by tapping into its plugin API)
  • Documentation
  • Consistent naming of things (so far copied Vue API for a lot of things - do the names match & make sense in this context?)
  • Optimization (Performance & Code Size)

Examples

A Counter component

/** @jsxImportSource @pago/reactive */
import { ref } from '@pago/reactive';

function Counter(props) {
  const count = ref(0);

  return () => (
    <div>
      <div>Count: {count.current}</div>
      <div>
        <button type="button" onClick={() => (count.current += props.step)}>
          Increment
        </button>
        <button type="button" onClick={() => (count.current -= props.step)}>
          Decrement
        </button>
      </div>
    </div>
  );
}

A Timer component

/** @jsxImportSource @pago/reactive */
import { r, ref, effect } from '@pago/reactive';

interface Props {
  step: number;
  delay: number;
}

function Timer(props: Props) {
  const count = ref(0);

  effect(onInvalidate => {
    const timer = setInterval(() => {
      // update is needed because we are reading from and writing to count
      count.update(current => current + props.step);
    }, props.delay);

    onInvalidate(() => clearInterval(timer));
  });

  return r(() => (
    <div>
      <div>Count: {count.current}</div>
    </div>
  ));
}

Setup

The easiest way to setup @pago/reactive for either React or Preact is to leverage the new jsxImportSource option and to set it to @pago/reactive.

Requirements:

  • React 17 or later
  • or Preact (todo: insert correct version)
  • Babel (todo: insert correct version)
  • or TypeScript (todo: insert correct version)

Per file

Specifying @pago/reactive as the JSX factory can be done using a comment at the beginning of the file. This should be supported by Babel & TypeScript.

/** @jsxImportSource @pago/reactive */

Babel

As specified in the babel documentation:

{
  "plugins": [
    [
      "@babel/plugin-transform-react-jsx",
      {
        "runtime": "automatic",
        "importSource": "@pago/reactive"
      }
    ]
  ]
}

Q & A

Is this ready for production?

Not yet.

Why ref().current instead of ref().value?

Because it allows us to do this:

import { ref, effect } from '@pago/reactive';

function CounterComponent() {
  const el = ref();
  effect(function updateDOMManually() {
    el.current.innerHTML = 'Hello World';
  });
  return () => <div ref={el}></div>;
}

Why does TypeScript complain about components not being components?

When you try to use a component like the one below with TypeScript in JSX, it'll inform you that () => Element is not a valid type for a JSX Element.

import { ref, effect } from '@pago/reactive';

function CounterComponent() {
  const el = ref();
  effect(function updateDOMManually() {
    el.current.innerHTML = 'Hello World';
  });
  return () => <div ref={el}></div>;
}

For the time being we don't have a better solution than to use the provided r function, which is basically a type cast that fakes the right type to make TypeScript happy.

import { r, ref, observe } from '@pago/reactive';

function CounterComponent() {
  const el = ref();
  observe(function updateDOMManually() {
    // `observe` is currently invoked immediately, rather than at the next tick
    // not sure if that behaviour is better or worse than delaying it a bit
    if (!el.current) return;
    el.current.innerHTML = 'Hello World';
  });
  return r(() => <div ref={el}></div>);
}

An alternative would be to use the wrap function explicitly.

import { wrap, ref, effect } from '@pago/reactive';
const CounterComponent = wrap(function CounterComponent() {
  const el = ref();
  effect(function updateDOMManually() {
    el.current.innerHTML = 'Hello World';
  });
  return () => <div ref={el}></div>;
});

reactive's People

Contributors

pago avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.