Skip to content

Instantly share code, notes, and snippets.

@ultrox
Last active August 16, 2024 23:08
Show Gist options
  • Save ultrox/5159cf0a57054ae92f0cae72f4706c97 to your computer and use it in GitHub Desktop.
Save ultrox/5159cf0a57054ae92f0cae72f4706c97 to your computer and use it in GitHub Desktop.
This is implementation of useMemo and useCallback directly from facebook/react, with some flow types removed and minor code changes.
/*type Hook = {|
memoizedState: any,
queue: UpdateQueue < any > | null,
next: Hook | null,
|};
*/
// Whether the work-in-progress hook is a re-rendered hook
let numberOfReRenders/*: number */= 0;
let isReRender/*: boolean */= false;
let firstWorkInProgressHook /*Hook | null */= null;
let workInProgressHook /*Hook | null */ = null;
function createWorkInProgressHook()/*: Hook */{
function createHook()/*: Hook */{
if (numberOfReRenders > 0) {
throw new Error('Rendered more hooks than during the previous render');
}
return {
memoizedState: null,
queue: null,
next: null,
};
}
if (workInProgressHook === null) {
// This is the first hook in the list
if (firstWorkInProgressHook === null) {
isReRender = false;
firstWorkInProgressHook = workInProgressHook = createHook();
} else {
// There's already a work-in-progress. Reuse it.
isReRender = true;
workInProgressHook = firstWorkInProgressHook;
}
} else {
if (workInProgressHook.next === null) {
isReRender = false;
// Append to the end of the list
workInProgressHook = workInProgressHook.next = createHook();
} else {
// There's already a work-in-progress. Reuse it.
isReRender = true;
workInProgressHook = workInProgressHook.next;
}
}
return workInProgressHook;
}
function areHookInputsEqual(nextDeps, prevDeps) {
if (prevDeps === null) {
return false;
}
for (let i = 0; i < prevDeps.length && i < nextDeps.length; i++) {
if (Object.is(nextDeps[i], prevDeps[i])) {
continue;
}
return false;
}
return true;
}
function useCallback(callback, deps) {
return useMemo(() => callback, deps);
}
function useMemo(nextCreate, deps) {
// setup
//currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
workInProgressHook = createWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps;
if (workInProgressHook !== null) {
const prevState = workInProgressHook.memoizedState;
const prevStateExists = prevState !== null;
const nextDepsExists = nextDeps !== null
if (prevStateExists && nextDepsExists) {
const prevDeps = prevState[1];
if (areHookInputsEqual(nextDeps, prevDeps)) {
const prevVal = prevState[0]
return prevVal;
}
}
}
// 1. initial(first) run
// 2. dependencies changed
// 3. no dependencies
const nextValue = nextCreate();
workInProgressHook.memoizedState = [nextValue, nextDeps];
return nextValue;
}
let render = 0;
function component(a) {
const me = useMemo(() => {
const data = Math.random()
render++
return data + " " + a;
}, [a])
console.log(me, 'result')
}
// component rendering
component("bip");
component("bip");
component("bip");
component("boop");
component("boop");
console.log(render)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment