Last active
August 16, 2024 23:08
-
-
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.
This file contains hidden or 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
/*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
https://github.com/facebook/react/blob/main/packages/react-server/src/ReactFizzHooks.js