Intermediate React, v4 Refactor Modal
This course has been updated! We now recommend you take the Intermediate React, v5 course.
Transcript from the "Refactor Modal" Lesson
>> We're gonna go piece by piece and we're going to migrate our application to TypeScript. And it's kinda cool, as long as everything says JS, it'll leave it in JS mode, which it won't do any necessarily checking on it. But for example, we're gonna go just start with modal.
[00:00:16] If you rename this to modal.tsx and the x is actually important here because TypeScript won't check React typings or it won't understand it well, unless we put the x there. So the x is actually required this time, okay? So as soon as I change this to x, now, it's giving me a bunch of errors.
[00:00:37] It's like I don't know what this is, I don't know what this is, I don't know what this is. And then we get to, basically play whack a mole with type errors. Okay, so first thing up here inside of this, now we can import types as well. So we're gonna import a FunctionComponent type and we're going to import a MutableRefObject type Okay?
[00:01:10] Good so far. Now, we're gonna say modal ur, a FunctionComponent, Which is pretty cool. So if you contrast that with our class components, it knows that it's a class component because you're telling it, it extends type component or extends class component, which knows is a type of component.
[00:01:35] Here, it doesn't know modal from any other functions. So we have to explicitly tell it, this is a FunctionComponent. That's what this colon means, the colon means I'm about to give you some more typing information, I'm about to narrow the typing down to specifically this. So now if you mouse over, like modal down here, it's gonna be like, I know what this is, this is a FunctionComponent that accepts no properties.
[00:02:02] Yeah, children just comes with everything, so that's fine. Okay? Here, elRef, it does know that it's a MutableRefObject, but it doesn't know what type it is. So we kinda have to tell it what kind of MutableRefObject it can be. So we're gonna say this is a ref object, MutableRefObject.
[00:02:24] Then we have to give it some parameters. So the way you give parameters to this MutableRefObject is with these angle brackets. Okay, and then inside of there, we're gonna say that this useRef is either going to contain a HTMLDivElement, HTMLDivElement, or it'll be null. Okay, it can only be one of those two things.
[00:02:58] So now later, I mean, just to show you if I say elRef.current = 5, it's gonna say, no, it can't do that. You told me that it can't do that, I'm not gonna let you do that, right? You told me it can be either a div or nothing and it cannot be a number.
[00:03:16] Whereas if I don't do that, it won't know, right? It won't know what it's supposed to be. Okay, and now everywhere, I have strong guarantees that this is either empty or it contains a div. Okay? So that's good so far. Now, we have this problem here, it's gonna say, hey, you told me that modal route might be null, so what about that?
[00:03:49] You can't call a pen child on something that's null, right? You can call and some of it's an HTML element, but I can't let you call it without you assuring me specifically that this is not null. So you get into this kinda like defensive programming stance. Now, I'm picturing like old martial art movies, it's very different from that.
[00:04:11] Modal, if no modalRoot or no elRef.current. So we're just gonna do a quick null check here. We're just gonna say return. Now, you might say like, well, it was never going to be null, our program was fine before. But we have to kinda like assure the type systems, this is definitely not gonna crash, cuz the type system doesn't know, right?
[00:04:40] All right, so there's that, that's fine. And then we have to do the same check here in the cleanup function. So if elRef.current, so if it does exist, then just go ahead and remove that from the DOM. And now this file is fully typed. Now, I will say that there are many ways to skin a cat in this particular situation.
[00:05:15] There's a bunch of ways you could have handled the MutableRefObject, there's other ways you could have handled the functionComponent. So there's not necessarily one correct way, there probably is like one best way, but I'm just showing you the way that I would do it. Okay, cool, so, The nice thing is that we only have to type the things that TypeScript cannot figure out itself.
[00:05:50] So for example, we have modalRoot here. This is always gonna be an HTML element or null, and it knows that because that's what you get back from document.getElementById, right? It just knows that that's what returns it said. I never had to tell, this is what modalRoot is, it's just like, okay, I got it, right?
[00:06:08] So anytime we're like, it can pull that information out, we don't have to go back and tell it later, you are this, right? For example, if this was like let, and I tried to say that modalRoot is now = 5, it's gonna get upset. It's like, no, I have a type for this before.
[00:06:29] If you want this to be true, then you have to go and tell me beforehand, hey, this could also be a number. In other words, TypeScript is pretty smart. You just have to kinda fill in the blanks where it could not be able to figure out what that is supposed to be.
>> How can I figure out what type of object I could need if I don't know MutableRefObject or any other React type? Is there a trick for that?
>> Yeah, it's always a bit of snooping around an investigation, that's a good question. You wanna know how I found it out, is I just moused over what useRef is.
[00:07:06] It's like okay, what does use ref give back? It gives back a React mutable object, or MutableRefObject, right? So a lot of times, you can just mouse over the function that you're calling, it'll tell you, I expect to give you this. So for example, getElementById, it gives you back, this is either gonna be an HTML element or it's gonna be null.
[00:07:29] You'll notice that I put HTMLDivElement up here. The reason why I did that, cuz I knew down here is gonna give you this. And I just specifically typed into a div because I knew down here I was creating a div. So elRef.current, this is definitely gonna be a HTMLDivElement.
[00:07:46] So that's the easiest way. I'm trying to think if there's anything additional, I think that that's almost like 99% of the sleuthing that I do is that way. The one thing to know is, with React is basically everything ends up, that it returns being a ReactNode, yes, you have the React.ReactNode.
[00:08:28] That's how I do it.