Skip to content

Instantly share code, notes, and snippets.

Forked from WebReflection/hooks-in-a-nutshell.js
Created January 4, 2021 20:59
Show Gist options
  • Save davidbgk/e09abd34164f0057b041adc710b011fb to your computer and use it in GitHub Desktop.
Save davidbgk/e09abd34164f0057b041adc710b011fb to your computer and use it in GitHub Desktop.
// WARNING: There's much more to know/do around hooks, and
// this is just a simplification of how these work.
// shared references, updated
// per each hook invoke
let execution = null;
let current = null;
let context = null;
let args = null;
// returns a function that updates known
// references each time it gets executed
// so that using useState within such function
// can retrieve all details related to the hook
const hooked = callback => {
// create a stack to incrementally retrieve
// or add new states whenever it's needed
const details = {i: 0, stack: []};
// return the hook function that resets index,
// update shared references, and then executes
return function hook() {
// reset the stack index
details.i = 0;
// update shared references
execution = details;
current = hook;
context = this;
args = arguments;
// invoke the original callback
return callback.apply(context, args);
// every time a hook invokes a useState
// the initial value is either known or new
const useState = value => {
// trap in this closure current details
// so that it's possible to re-invoke the hook
// with latest provided context and arguments
const hook = current;
const ctx = context;
const rest = args;
// grab current stack and its index
const {i, stack} = execution;
// increment the stack index so that the next
// useState(value) will get its slot
// if the stack does not know about this slot
if (i === stack.length) {
// store the initial value in the stack,
// making the current stack[i] reachable
return [
// the last value stored at this index
// or the one we've just pushed
// the update function that re-invoke the hook
value => {
// update this stack value with a new one
stack[i] = value;
// execute the hook one more time,
// so that everything gets synchronized
hook.apply(ctx, rest);
// this will repeat this recursive dance
// until no state update happens
// EXAMPLE - Counter factory
// the hooked callback can be defined a part
// as long as it's invoked only once hooked
const toBeWrapped = start => {
const [num, update] = useState(start);
console.log(`Counting: ${num}`);
setTimeout(update, 1000, num + 1);
// in this case the Counter returns, each time,
// a new hooked version of the same callback
// and it executes it right away
function Counter() {
return hooked(toBeWrapped).apply(this, arguments);
// read a counting from 0 to N in console
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment