### Intro
We are going to dive into useRef and useMemo. If you are unfamiliar with either of these hooks I recommend reading about them here: useRef, useMemo
### useRef
Let's start with useRef because it is the simpler one (see on github)
-- CODE language-js -- function useRef<T>(initialValue: T): {|current: T|} {
currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
workInProgressHook = createWorkInProgressHook();
const previousRef = workInProgressHook.memoizedState;
if (previousRef === null) {
const ref = {current: initialValue};
if (__DEV__) {
Object.seal(ref);
}
workInProgressHook.memoizedState = ref;
return ref;
} else {
return previousRef;
}
}
First, let’s simplify the code to make it easier to understand:
-- CODE language-js -- function useRef(initialValue) {
const previousRef = workInProgressHook.memoizedState;
if (previousRef === null) {
const ref = {current: initialValue};
workInProgressHook.memoizedState = ref;
return ref;
} else {
return previousRef;
}
}
MemoizedState is nothing but an object. It’s a fancy name that doesn’t apply in this situation because nothing is memoized. All this is doing is storing some data. That is it. Nothing more. Creating a ref gives you a place to store whatever you want. It’s called useRef or use reference because the ref holds a reference to your storage. useRef returns {current:value}. Current is whatever you want it to be. And current can be set at any time to a new value.
-- CODE language-js -- Const ref = useRef(3); //{current:3}
Ref.current = 4 //{current:4}
Ref.current = {foo: ‘poo’} //{current: {foo: ‘poo’}}
There you go. useRef is simple.
### useMemo
Now for useMemo (see on github)
-- CODE language-js -- function useMemo<T>(nextCreate: () => T, deps: Array<mixed> | void | null): T {
currentlyRenderingComponent = resolveCurrentlyRenderingComponent();
workInProgressHook = createWorkInProgressHook();
const nextDeps = deps === undefined ? null : deps;
if (workInProgressHook !== null) {
const prevState = workInProgressHook.memoizedState;
if (prevState !== null) {
if (nextDeps !== null) {
const prevDeps = prevState[1];
if (areHookInputsEqual(nextDeps, prevDeps)) {
return prevState[0];
}
}
}
}
if (__DEV__) {
isInHookUserCodeInDev = true;
}
const nextValue = nextCreate();
if (__DEV__) {
isInHookUserCodeInDev = false;
}
workInProgressHook.memoizedState = [nextValue, nextDeps];
return nextValue;
}
And again let’s simplify it:
-- CODE language-js -- function useMemo<T>(nextCreate, deps) {
workInProgressHook = getMeMyUseMemoHook();
const nextDeps = deps === undefined ? null : deps;
if (workInProgressHook !== null) {
const prevState = workInProgressHook.memoizedState;
if (prevState !== null) {
if (nextDeps !== null) {
const prevDeps = prevState[1];
if (areHookInputsEqual(nextDeps, prevDeps)) {
return prevState[0];
}
}
}
}
const nextValue = nextCreate();
workInProgressHook.memoizedState = [nextValue, nextDeps];
return nextValue;
}
There is more going on here than with useRef but not much.
A few things to note:
With that in mind this code does the following:
useMemo is basically a memoized useRef. For example, with no dependencies, the following useMemo is functionally equivalent to useRef
-- CODE language-js --const memo = useMemo(() => ({current: 8}), []);
const ref = useRef(8);
Both of the above will result in a const equal to {current:8} where the current property can be changed whenever you like.
TLDR: It's good to look at the code to demystify the magic of the unknown
Are you ready to build something brilliant? We're ready to help.