- Now the next hook I wanna talk about is the use ref hook,
which is unfortunately by far the most annoying hook to work
with in React when it comes to TypeScript,
'cause they made some really weird decisions
when they created it.
So you notice immediately I have multiple errors inside
of my code with this code that I have written here.
So I have an input ref, and I just set it to a use ref,
and I'm trying to define that on my input down here.
You may think that this should work fine but it doesn't.
Obviously if I hover over this area,
you'll notice it's really confusing what's going on.
The reason that this is so confusing
is because this ref prop right here inside of React,
they either expect you to pass undefined,
which obviously we're not doing, or a legacy ref.
So if we go a little further and look at this legacy ref,
you'll notice it can be a string.
Just ignore that, that's legacy.
That's why they call it legacy ref,
or it expects a ref.
And this ref object here
is either a callback or it's going to be a ref object.
This callback is how we talked
about how you can use the use callback hook inside a ref.
So this obviously doesn't apply.
So the only thing we care
about right here is this either ref object
or it expects us to pass along null.
And a ref object is just a normal object
that has a current property on it.
So it either expects us to pass along a ref
or a value of null,
but specifically we cannot pass undefined.
A ref must always be null or an actual ref object
when we pass it to an input.
And you'll notice that this by default sets
to undefined 'cause we pass in nothing.
So we actually need to pass along null into this,
because now we actually get a ref object
that is null and not undefined.
So if we look at this,
you can see it's an object that has the type
of null as the default type.
So it's really important
if you're ever using an HTML element and you wanna hook
up the ref, you need to set knoll as the value.
Another thing that you need to do when you're working
with an actual ref is you need to type it,
because right now this is a type specifically of only null.
It can be nothing except for null.
So obviously when I come in here, do input ref.current
and I wanna get like the value of my input
or I wanna focus on my input, none of that's working at all.
Instead, I need to pass
in the generic here, and I need to pass
in the HTML input element.
Pretty much every single HTML element,
you can just start with all capitals, HTML,
and then search for whatever your element is.
In my case, it's an input element,
and that's going to give me the type for that.
And now you can see that I hover over this,
it is saying that this is a type of HTML element.
And if I make sure I just put in the question mark here,
because this is possibly null
'cause it can be null or an HTML element,
you can now see everything is working just fine.
And if I go
to this use ref definition right here,
you'll notice that it returns to us a ref object,
and if we go to this,
you can see that this is an immutable object,
it is read-only.
So it's really important to understand
that this is giving me back a read-only version.
So I can't actually set my current to anything at all.
If I tried to set something, it's essentially saying,
"Hey this is read-only, I cannot set it."
So if you pass along Noel to a ref, you're telling React,
"Hey, you know what?
You handle this ref for me.
I don't wanna mess with this ref, you handle it for me."
And I'm only pretty much going to do that in the case
where I pass it to a component like this.
But sometimes you have a ref, for example,
this value ref, where you don't want to pass it
to a component and you wanna be able to mutate it yourself
'cause you want to handle this reference yourself.
In those cases, you essentially need
to do the exact same thing but don't pass along null.
So here, I need to give it a generic type
because right now it's just assuming the type is undefined.
So here I'll give it a generic type,
and we're saying that this is a number.
If I do that, you can now see my code works fine
and this is either undefined
or it's going to be an actual number.
Or if I pass it a default,
I can just remove this generic type
because it just assumes what the value's gonna be.
You can see it assumes it is going to be a number
and now again everything is working just fine.
So ref is really annoying
in the way that they implemented it.
If you want to use a ref
with an input component or an HTML element,
you need to make sure that you pass along the generic
for what the HTML element is and then pass along
null as the default value,
'cause if you don't do this, it's not going to work,
you're gonna get an error.
And if you're using a ref that just has not
a HTML element hooked up to it,
never pass no as the default value.
'cause if you do that, you're going to mess everything up.
It's going to think you want to work with an HTML element
and it's not gonna let you mutate it.
Instead, you need
to either pass it undefined as the default value
or whatever your actual default value is.
And you may optionally need to specify the exact type here.
If you either have no default value
or you have a really generic default value,
like an array like this,
you need to make sure you type it as a number array.
And then if I change this to an array,
you can see everything is working fine.