‫So in this video
‫we're gonna go back to our project
‫and build a simple modal window component
‫using React's portal feature
‫so that we can then convert this modal
‫to a compound component in the next video.
‫So as I have mentioned earlier here in our cabins page
‫we actually want this form to add a new cabin
‫to appear in a modal window.
‫So not just here rendered on the page
‫but we want basically a new window to open on top of this
‫and then display our form in there.
‫And so let's now build that reusable modal component.
‫Now we already have a file for that.
‫So here in the UI folder we have modal.jsx
‫which already contains these three styled components for us.
‫And so now all we have to do is to basically assemble these
‫and then use this modal in our application.
‫So just to test this now and to return something
‫let's use this StyledModal component that we have up there.
‫And then let's just render Modal.
‫So we have this StyledModal here
‫which contains some styles
‫and we will actually take a look at that a bit later.
‫So for now, let's just include this modal here.
‫And so for that, let's come to the cabins page.
‫And so right now here we have that logic
‫where we have the button
‫and then, conditionally based on the state,
‫we display the form.
‫Now for the modal, we will actually have something similar
‫but let's move all this logic here to a separate component
‫because as we said initially
‫we want all of these pages here to be as simple as possible.
‫So we don't want them to have any state or any effects.
‫So in our cabin's folder
‫let's just create a component called AddCabin.
‫And so this is where we will then call the modal.
‫So let's see if we can use some of this right there.
‫So maybe let's grab all of this here, place that here.
‫Also the state, even though we are going to change the name.
‫And yeah, then here, let's get rid of all of this
‫and here simply render that AddCabin component.
‫So let's get rid of all of these unnecessary imports.
‫And so this is a lot cleaner.
‫And then of course we need to correct all the stuff here.
‫So importing the state, the button
‫and then also deform itself.
‫All right, and now I just want to change this name here
‫from showForm to isOpenModal.
‫So isOpenModal and just like this.
‫And for now here, whenever the modal is open
‫let's just show that modal.
‫So what we just worked on later.
‫So let's re-render this.
‫And so now let's see what happens.
‫And indeed there is or modal window,
‫but of course, now we want to make this a bit more reusable.
‫And so we will allow this modal window
‫to receive some custom content.
‫And so that content is, as you can imagine,
‫going to be the CreateCabinForm.
‫So for that, we will just pass this in.
‫And then inside the modal we will use the children prop
‫to receive this form.
‫So here it's actually Modal.
‫And here this should be self-closing.
‫All right.
‫And of course, that doesn't change anything here
‫because now we need to go over the modal
‫and accept the children prop
‫and then display that right here.
‫Now we don't know what kind of element
‫we are going to get here.
‫And so let's actually wrap whatever children
‫that we receive here, which we don't know what they are,
‫inside a div like this.
‫And so this is starting to look like something here.
‫The styling is maybe a bit off, but we will fix that later.
‫So what matters is that this modal is actually
‫already nicely centered on our page.
‫And so that's because of this fixed position right here
‫and then this top, left and transform.
‫But now let's also use this overlay component here
‫which will add a subtle background color
‫and will make the background blurred.
‫So that will give the whole thing a bit of a nicer look.
‫So, Overlay like this.
‫And beautiful.
‫Next up, we also need a way of closing the modal.
‫So that's a pretty common functionality, right?
‫And so we need to add a button here.
‫And again, we already have that button here.
‫And so let's just use it here also inside the StyledModal.
‫So, Button.
‫And then here, let's use, again, an icon from our library.
‫So this one right here.
‫And so there it is.
‫But of course, now as we click here
‫nothing is going to happen.
‫And the reason for that
‫is that we don't really know how to close this modal, right?
‫So we didn't pass any prop in here
‫and therefore nothing happens.
‫So how can we actually close this modal?
‫Well, remember that the modal is being opened
‫because of this external state right here.
‫So this state that is actually living
‫outside of the modal, right?
‫So whenever this here is true
‫then the modal will be rendered, but if not, then not.
‫And so in order to close the modal,
‫we basically now need to pass in
‫this setIsOpenModal function
‫or at least some function that depends on that.
‫So let's pass in then the onClose prop
‫which will be dysfunction that I just mentioned.
‫So let's create a callback function here
‫which will setIsOpenModal to false, right?
‫So by calling this function
‫this will then set the state back to false
‫and the modal will close.
‫So let's accept that prop here. onClose.
‫And then here we just need to wire that up
‫with the onClick event handler.
‫So, onClose and there we go.
‫Let's open it up again
‫because we also want the same functionality
‫whenever we click here on this cancel button.
‫So that also makes sense to close the modal
‫and it would even make sense to close it
‫whenever the new cabin has been created.
‫So that's something pretty usual
‫that you see in web applications.
‫And so let's try to do something similar.
‫And for that, we have to do exactly what we did earlier
‫which is to also pass in a prop here
‫with this same function, right?
‫Because otherwise the form has no way of knowing
‫how to actually close the modal.
‫Now here, let's even call this prop onCloseModal.
‫So to be a bit more specific.
‫And then let's come here and then let's accept that prop.
‫So, onCloseModal.
‫And then basically what we want to do...
‫Well, first of all, here on the reset button...
‫So this cancel button, let's add the onClick prop.
‫And then here we could just use onCloseModal.
‫However, we do not know
‫whether this form will ever be reused in another place,
‫not inside the modal.
‫And so if this form is ever used
‫in some place where it isn't contained in a modal
‫then it's not going to receive
‫this onCloseModal prop, right?
‫And so that means
‫that we need to call this function here conditionally
‫because again, it might not even exist.
‫And so in that case, if it doesn't exist,
‫then this will create a bug.
‫So let's actually create a callback here
‫and then we can conditionally call a function
‫with the optional chaining operator.
‫So that's really convenient.
‫And so if this is undefined
‫then the function will not get called
‫because of this optional chaining operator.
‫All right, now let's copy this
‫and then do the exact same thing also right here.
‫So onSuccess, so after the cabin has been created
‫or after it has been edited,
‫then let's also close the modal.
‫So let's try that with this button.
‫And nice. So that works.
‫And I'm not gonna try creating a new cabin
‫because that's not really necessary.
‫Now, since we are already in this form component
‫let's quickly fix the styling as well.
‫So here we basically want to get rid
‫of all the space right here
‫in case that the form is rendered in a modal.
‫So let's come here to the form and then add a prop here.
‫So then in our styled component, we will receive this prop
‫and change the styling accordingly.
‫Now, the way in which we know
‫whether this form is being rendered in a modal
‫is if it received the onCloseModal prop.
‫So that's a nice way or a nice trick of checking that.
‫And so let's do onCloseModal.
‫If it exists, then here we want to create the modal prop.
‫So set the type prop to modal.
‫And otherwise, let's just call it regular.
‫All right, and so now let's check here for these two props.
‫So modal and regular.
‫So let's go to our form component
‫and that, again, works by hitting the Command
‫or the Control key at the same time as clicking.
‫Now here, we actually already have the code
‫for using those props.
‫So if the form type is modal, then it will get this styling
‫and otherwise it will get this styling.
‫But here, let's actually be a bit more explicit
‫and check for the regular type.
‫So the regular prop that we specified earlier as well.
‫And then let's make that the default prop.
‫So, Form.defaultProps.
‫So just like we did earlier.
‫So the type by default should of course be regular.
‫All right, so let's check this.
‫And beautiful.
‫So this looks a lot better than before
‫and it works just nicely.
‫However, there is still one important improvement
‫that we need to do.
‫So we can close all of this. All of this now works nicely.
‫But yeah, as I was saying, let's now improve this here
‫using something called a React portal.
‫So a React portal is a feature
‫that essentially allows us to render an element
‫outside of the parent component's DOM structure
‫while still keeping the element in the original position
‫of the component tree.
‫So in other words, with a portal
‫we can basically render a component
‫in any place that we want inside the DOM tree
‫but still leave the component
‫at the same place in the React component tree.
‫And so then things like props keep working normally.
‫And so this is great and generally used for all elements
‫that we want to stay on top of other elements.
‫So things like modal windows, tool tips, menus and so on.
‫And since we are building a modal right now
‫I thought it was a good idea to show you this feature.
‫So before we start
‫let's actually take a look at the current situation.
‫So when we open the modal, let's inspect this.
‫And so here in our DOM tree...
‫Well, where is it actually?
‫And yeah, this is the one.
‫So this is basically our modal window.
‫And of course right now
‫it is simply inside the DOM structure of our page.
‫So we have our main
‫and then in there this is probably the table
‫and then these are all the rows.
‫And yeah, then after that comes our modal.
‫But now with a React portal, as I was just saying
‫we can basically render this component
‫completely outside of this DOM structure
‫and really render it anywhere that we want.
‫So let me quickly show you how.
‫So it's actually really easy.
‫So instead of just returning this JSX here
‫we return the results of calling createPortal.
‫So, createPortal.
‫And this one is actually not part of React
‫but of React DOM, which actually makes sense
‫because this really is about placing some JSX in the DOM.
‫Now then this function here receives as the first argument
‫the JSX that we want to render.
‫And then as the second argument,
‫a DOM note where we want to render this JSX.
‫And so let's just do this in the document body.
‫And so that we can select
‫simply by writing document.body.
‫All right.
‫But it could of course be also any other element as well
‫and we could select it, for example,
‫using document.querySelector or any other way.
‫But anyway, let's now go back to just attaching this
‫to the document body,
‫even though some developers say that this is not ideal,
‫but actually it does work just fine.
‫So let's just reload here, then let's open the form.
‫And now notice how the modal window
‫is actually a direct child element of the body element.
‫And so that's because we selected that body right here.
‫And so the reason for that
‫is that here we selected that body element
‫to be the parent element of whatever we want to render.
‫All right.
‫And so this now essentially lives completely outside
‫of the DOM structure of the application itself,
‫which lives right here inside this root div.
‫Now, what's nice about this, as I was saying,
‫is that inside the component tree
‫the modal is still at the exact same place.
‫And so that's why we can still pass all the props into it
‫that we want.
‫So it's still a child element here off AddCabin
‫even though in the DOM it no longer is.
‫So this portal basically is called a portal
‫because it allows us to create an invisible tunnel,
‫so like a portal,
‫from the place where the component is in the component tree
‫to another place in the DOM tree.
‫But now you might be wondering,
‫this worked really great already in the beginning
‫with just regular CSS positioning, so without the portal.
‫And so why do we even need to use this portal?
‫Well, the main reason why a portal becomes necessary
‫is in order to avoid conflicts
‫with the CSS property overflow set to hidden.
‫So many times we build a component like a modal
‫and it works just fine,
‫but then some other developer will reuse it somewhere else
‫and that somewhere else might be a place
‫where the modal will get cut off
‫by a overflow hidden set on the parent.
‫So this is basically all about reusability
‫and making sure that the component will never be cut off
‫by an overflow property set to hidden
‫on some parent element.
‫So in order to avoid this kind of situation
‫we simply render the modal completely outside
‫of the rest of the DOM.
‫So basically on top of the DOM tree as we just did here.
‫All right, so hopefully this made sense.
‫And with this, we finished our first version of the modal.
‫However, this modal does contain a few problems
‫and most importantly, the way in which we open the modal.
‫And so that's why in the next lecture
‫we will actually convert this to a compound component.