Last active
August 7, 2020 14:57
-
-
Save ProdigySim/c6bb7f7a45489f0331a4b622646cc2fc to your computer and use it in GitHub Desktop.
Thinking about making hooks a language generic feature supported by transpilation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Stateful object used to track hook execution order | |
class HookStack { | |
private stack: unknown[] | |
private stackPtr: number = 0; | |
private isInitialStack: boolean; | |
constructor(stackMemo?: unknown[]) { | |
if (stackMemo) { | |
this.stack = [...stackMemo]; | |
this.isInitialStack = true; | |
} else { | |
this.stack = []; | |
this.isInitialStack = false; | |
} | |
} | |
getOrCreateSlot<T>(fn: () => T): T { | |
if (this.stackPtr < this.stack.length) { | |
return this.stack[this.stackPtr++] as T; | |
} | |
if (this.isInitialStack) { | |
const newSlot = fn(); | |
this.stack.push(newSlot); | |
this.stackPtr++; | |
return newSlot; | |
} | |
throw new Error("Please don't use hooks in conditionals and stuff.") | |
} | |
} | |
function useState_raw<T>(stack: HookStack, intiialValue: T) { | |
const slot = stack.getOrCreateSlot(() => { | |
return { value: intiialValue }; | |
}); | |
return [slot.value, (newValue: T) => slot.value = newValue] as const; | |
} | |
// Language transforms function to this signature | |
declare function useState<T>(initialValue: T): [T, (val: T) => void]; | |
const MyComponentA = () => { | |
const [count, setCount] = use useState(0); | |
return <button onClick={ () => setCount(count+1) }>{ count }</button>; | |
} | |
// Language compiles function down to this: | |
const MyComponentA_comp = (() => { | |
// component "memory" storage | |
const memoStack: unknown[] = []; | |
const body = (stack: HookStack) => { | |
const [count, setCount] = useState_raw(stack, 0); | |
return <button onClick={ () => setCount(count+1) }>{ count }</button>; | |
}; | |
return (..args) => body(new HookStack(memoStack), ...args) | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment