This course has been updated! We now recommend you take the Complete Intro to React, v8 course.
Transcript from the "Portals, Refs, and Q&A" Lesson
[00:00:00]
>> So who likes modals? Nobody. They're like the worst objectively. No, no, I do not believe you. You actually don't like models. Let me tell you. Just kidding. You might like my models. I just don't understand why. [COUGH] Models are terrible user interface experiences, but we still use them everywhere because we haven't discovered a better way as developers to inform users that something is happening.
[00:00:27] So despite the fact that I'm railing on models right now, I'm going to show you how to make models. Because someone at your next job some lovely Program Manager like me, he was like, hey, we should have a model here. I hate myself. Just kidding. Alright, so let's go to that.
[00:00:47] Let's go do models. So the thing about models is like this has to show up like in front of the user, right? It's got to show up in front of all of the stuff in front of you. So let's say inside of pet for whatever reason, right? So here inside of our sorry inside of details, I wanted to trigger a modal, right?
[00:01:05] If someone clicks adopts this right, then I want to pop up a modal but my problem with react at the moment is that where is details? Well details is inside of the div that's inside of app and then have to go into details. So if I try and show like modal right here, it's going to be still be inside of the details component.
[00:01:28] In other words, I want to render something somewhere else, in another part of my application from within one of the components. It's kind of a weird problem and it used to be pretty difficult to solve. You either had to get some weird CSS going on or you had to work outside of React, which is not a good idea either.
[00:01:52] Well, the React team came up with the idea of a portal. And it's a million times easier to use than it used to be. So I want you to open your index dot HTML that we have. Okay, here, above route I want you to make another div. And I want it to be ID equals modal.
[00:02:19] And don't put anything in modal. So now we can render outside above route objectively, right, because route is still limited to this and then we can render sometimes into this when we need to. So it's another like render point. I want you to make a new file, call it modal.js.
[00:02:44] And we're going to say import use effect. Use ref. We also may talk about ref, which is another fun one. From react. Here we're going to say const. Modal route equals document. Get element by ID Modal. This is going to be what we're going to render into. We're going to say const.
[00:03:16] Modal. Now we forgot that as well. Up here we also have to import create portal from react-dom Okay, const modal equals, I'm going to pull out children from the props. Because modal doesn't actually care what it's going to render, right? It's just going to render whatever is passed into it.
[00:03:42] So const children, We're going to make a ref. So let's talk about Refs here in just a second, elRef = useRef null. And then I want to say if elRef.current. So if this doesn't exist then elRef.current = document.createElement('div'). So let's talk about what happened here. Let's talk about useRef first.
[00:04:32] We'll get more into this intermediate react I have a whole section talking about what it is. But elRef or Ref is a container for state that you want to survive past render cycles. So for example, we have this elRef current equals to document create Amanda Dev. We only want one dip.
[00:04:51] We want to we don't want to create a new div on every rerender. We want to have exactly one div all the time. So what we're doing here is we're saying, hey, if this elRef doctrine hasn't been initialized, we want to initialize it to be this div and then we want this div to survive past renders until you dispose of the modal altogether and then you'll destroy it.
[00:05:13] Right? But until then, I just want one I want exactly one because I don't. This document I create is not cheap, right?. So you don't wanna just rerender it every single time. And we also need to hold on to the same one so that eventually we can dispose of it.
[00:05:26] Does that make sense?. So if you want to have like some piece of state that you want exactly one of instead of a component, you can use these things called Refs. They're useful for other things but they're particularly useful in this particular case as well. All right, so here we're going to say use effect.
[00:05:51] And then, if not so low in the code there. We're going to say modalRoot.append child. ElRef, .current. So we're going to append this to the dom. And then, we also need to clean up after we're done. So we're going to read we talked about this earlier but this is how you clean up an effect.
[00:06:26] So whenever we're done we're going to say module route.remove child elRef.current. And then we only want this to happen once so we're going to give it an empty array there. So basically what we're saying here is, hey, whenever you get created, insert it into the dom, whenever you are done, remove me from the dom, and this prevents memory leaks, otherwise you'd be leaking divs every single time that you created a modal and then unrendered a modal, that makes any sense.
[00:07:07] Okay, then down here, we're just going to say return create portal. Div. We're going to wrap this in a div. I know it's a bit of modal soup or a div soup, but the reason being is that sometimes children can be like a list of elements, and top level elements always have to be a single thing.
[00:07:35] You can use fragments in other places. And we'll talk about fragments later. But for now, just trust me put a div here. It'll make your life easier. Otherwise you'll get some random errors sometimes, so I'm going to put children here. And then we're going to say elRef.current, which is going to be this div that we created, right?
[00:08:04] And there we go. Now we can say export default, Modal. And now we can use this modal anywhere that we want to, this is now a reusable modal component. Which is pretty great, right? But now we can render modals whenever we need to, from any part of our application.
[00:08:26] Yeah, that's a good question. So like, why would I use a reference to that like I why don't I just say like const container equals blah right or for this. So I think for actually this particular use case of modal we could have because we're only going to have one modal at a time.
[00:08:50] I have to try this, but this is what occurs to me. However, what happens if we have multiple models at the same time? One, fire designer, that's my first thing I'd say about that. Secondly, you're not always going to use portals for that reason, like imagine if you had a portal that renders to a sidebar and another one that renders to the bottom bar and those kinds of different places.
[00:09:15] Those could have multiple different containers that they'd be referencing. But if you have a global variable like this, they're all going to be referencing the same div. And that's not actually what you want. You want each modal to be totally self contained, right? So that I can have on each, portal as it were all right?
[00:09:34] You want each portal to be totally contained, right? So this makes it unique per instance of modal. Which is why you need to use a ref so that each one has its own. You can't just reference the same global one. Kind of an advanced use case, but suffice to say, if that didn't make any sense to just trust me until you understand that .Yeah
[00:10:01]
>> Do all refs need to be cleaned up?
>> Nope. Just ones that need to be cleaned up [LAUGH] So for example, this one gets appended to the dom. So even though I stopped referencing it, it's still gonna be in the dom, right? So the dom is holding on to it.
[00:10:23] So if I had like rendered and unrendered, a bunch of models, I would have 50 divs, empty divs just sitting there because it's appending into the dom. So not every reference to be cleaned up, but everything from the dom that gets appended the dom does have to be cleaned up.
[00:10:39] Good question. Other questions?
>> Yeah, can you clarify a bit more on what the create role is doing? A bit confused with it.
>> Let's open our app.js and just scroll to the bottom here. It's basically what react dom is rent doing here. So it's just saying hey, render me out to wherever I'm meant to go, right?
[00:11:04] So in this particular case this one renders out to route. This one's saying hey, put whatever I have in children here, put this div into, This. So it's rendering out to the dom at that location. That makes sense?
>> Why not use the React dom that's my thing here.
[00:11:27] So like you can't use the same thing, again, like the React dom dot render for the modal as well.
>> No, because you're rendering basically outside of itself, right? In other words, it might have been able to overload it but it would have been confusing. So they created two separate methods for it.