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'
All hooks behave as close as possible to their React counter part, with a notable difference for useEffect
.
- Basic Hooks
- useState
- useEffect
- useContext experimental
- Additional Hooks
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.
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);
}
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.
This hook is strictly React oriented and have no meaning in current augmentor world.
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.