JSPM

  • Created
  • Published
  • Downloads 5970
  • Score
    100M100P100Q115825F
  • License ISC

Extensible, general purpose, React like hooks for the masses.

Package Exports

  • augmentor

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (augmentor) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

augmentor

Build Status Coverage Status Greenkeeper badge WebReflection status

Extensible, general purpose, React like hooks for the masses.

Code Pen playground.

Include via:

  • CDN as global utility, via https://unpkg.com/augmentor
  • CJS via const {default: augmentor, useState} = require('augmentor')
  • ESM via import augmentor, {useState} from 'augmentor'
  • ESM CDN via import augmentor, {useState} from 'https://unpkg.com/augmentor?module'

Available Hooks

All hooks behave as close as possible to their React counter part, with a notable difference for useEffect.

A DOM oriented useEffect

If you'd like to have DOM nodes connect/disconnect hooks, similarly to how React mount and unmount work, consider using dom-augmentor or keep reading to understand how to write your own.

example

You can test this example directly on Code Pen.

import augmentor, {useState} from 'augmentor';

// augment any function once
const a = augmentor(test);
a();

// ... or many times ...
const [b, c] = [test, test].map(augmentor);
b();
c();

function test() {

  const [count, setCount] = useState(0);

  // log current count value
  console.log(count);

  // will invoke this augmented function each second
  setTimeout(() => setCount(count + 1), 1000);
}

What's different in useEffect

With React components, when you pass an empty array to useEffect the effects, and their cleanup, would run only on component mounted or unmounted.

However, being augmentor a general purpose utility, there is no notion of any component, so that an empty array will result into an effect that will run once, but it'll never clean up unless explicitly forced through the augmented function .reset() method.

import augmentor, {useEffect} from 'augmentor';

const effected = augmentor(() => {
  useEffect(
    () => {
      const i = setInterval(console.log, 1000, Math.random());
      return () => clearInterval(i);
    },
    []
  );
});

// will start showing the random number every second
effected();

// will cleanup the effect in 5 seconds
setTimeout(effected.reset, 5000);

This behavior might be OK in some well orchestrated case, but it's quite unpractical in the real world.

To help developers define whenever effects should run, or cleanup, instead of passing an empty array one can pass a callback which will be executed right after the augmented function is invoked, receiving effect callback, and the augmented function returned value.

In this case, the augmentor will invoke such callback once, and never again, for the whole augmented lifecycle (unless forced via explicit .reset()), so that it's safe to setup an effect behavior within the provided effects handler.

import augmentor, {useEffect} from 'augmentor';

const effected = augmentor(() => {
  useEffect(
    () => {
      const i = setInterval(console.log, 1000, Math.random());
      return () => clearInterval(i);
    },
    lifecycleHandler
  );
  // returning some value
  return 5000;
});

// will start showing the random number every second
// and it will automatically clean up after 5 seconds
effected(); // returns 5000

function lifecycleHandler(callback, result) {
  const cleanUp = callback();
  // returned value used to clear the timer after 5 seconds
  setTimeout(cleanUp, result);
}

You can see this mechanism in practice applied through the neverland library, where passing an empty array will implicitly result into observing nodes through the DOM.

About useImperativeMethods

This hook is strictly React oriented and have no meaning in current augmentor world.

Create your own hook

Beside using any of the already implemented hooks to create your own would work just fine, you could also take advantage of internals used to create other hooks.

The augmentor core provides indeed utilities to make your own hook, for your own library, and export these like any other.

Following a useUpdate example based on these internals.

import {setup, stacked, unstacked, uid} from 'augmentor/esm/core.js';

// create a unique identifier for this hook
const id = uid();

// add to each runner setup a new stack for this hook
setup.push(stacked(id));

// export the updater
export const useUpdate = value => {
  const {i, stack, update, unknown} = unstacked(id);
  // if unknown, add this this hook stack any value
  // this could be also the update function itself
  // which will re-invoke the callback any time it's used
  if (unknown)
    stack.push(update);
  // return the current stack position at index `i`
  return stack[i];
};

Now import the code in your project, and see every time an updater is invoked the whole callback is re-executed.

import augmentor from 'augmentor';
import { useUpdate } from './use-update.js';

const zero = augmentor(increment);

zero({value: 0});

function increment(ref) {
  // used to invoke again the augmented function
  const update = useUpdate();
  setTimeout(update, 1000);

 // log and increment the reference value
  console.log(ref.value++);
}

You can test both files, as CJS version, through the example folder.