What's the difference between useRef(null)
and useRef(undefined)
(or just useRef()
)?
In TypeScript, the results end up with different types:
const undefinedRef: React.MutableRefObject<undefined> = useRef(undefined)
conse noArgRef: React.MutableRefObject<undefined> = useRef()
const nullRef: React.MutableRefObject<null> = useRef(null)
This also has further consequences, when passing the ref to another element:
const nullRef = useRef(null)
<div ref={nullRef} /> // this works
const undefinedRef = useRef()
<div ref={undefinedRef} /> // compiler failure!
/*
Type 'MutableRefObject<undefined>' is not assignable to type 'string | ((instance: HTMLDivElement | null) => void) | RefObject<HTMLDivElement> | null | undefined'.
Type 'MutableRefObject<undefined>' is not assignable to type 'RefObject<HTMLDivElement>'.
Types of property 'current' are incompatible.
Type 'undefined' is not assignable to type 'HTMLDivElement | null'.ts(2322)
*/
Despite the compiler failure, it still works for my use case (using the useClickAway
hook from react-use
)
What's the impact at this, looking beyond the TypeScript types?
Here's a CodeSandbox that recreates the failure: https://codesandbox.io/s/prod-resonance-j9yuu?file=/src/App.tsx
There isn't any difference between
const undefinedRef: React.MutableRefObject<undefined> = useRef(undefined)
conse noArgRef: React.MutableRefObject<undefined> = useRef()
both of them have undefinedRef.current
and noArgRef.current
as undefined.
However
const nullRef: React.MutableRefObject<null> = useRef(null)
will have nullRef.current
assigned as null
The only impact this will have in your code is when you actually try to access a property from within current or try to check the typeof ref
For instance typeof nullRef.current
will be object
and an if condition like
if(typeof nullRef.current === "object") {
// This will get executed only for nullRef and not for the other two refs
}
I believe something like const ref = useRef<SomeType>(null)
will make the reference readonly.
See this note from TypeScript cheatsheet.
there are overloads for useRef such that if you use a type param T vs T | null the resultant object is different:
refObjectToPassIntoRefProp = useRef<HTMLDivElement>(null) // @type = { current: HTMLDivElement | null } const refObjectYouMaintain = useRef<HTMLDivElement | null>(null) // @type = { current: HTMLDivElement | undefined } const refObjectYouMaintainToo = useRef<HTMLDivElement>()
With the first, the current property of the object is read-only to you, the consumer. It's meant to be passed into React as the pointer is maintained by React. In practice, you can still mutate the current property of something you pass into React but it's not recommended as React is supposed to be the owner.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With