‫So let's convert the first version
‫of the modal component that we just built
‫to a compound component.
‫And the reason why that is necessary
‫is that this modal that we have built is really not ideal
‫when it comes to the state management
‫and to the way in which we actually render this modal.
‫So remember how we render the modal right here
‫based on this isOpenModal state.
‫Now the problem with this is that we really do not want
‫the component who uses the modal to be responsible
‫for creating this piece of state
‫and to keep track of whether the modal is open or not.
‫So again, it shouldn't be the task
‫of the AddCabin component here to track
‫whether right now the modal should be displayed or not.
‫So instead, the modal component itself should actually know
‫whether it is currently open or not,
‫and so it should keep this state internally.
‫So it should track this basically encapsulated
‫inside the component.
‫And then the component should give us simply a way
‫to open the modal and also a way to pass in the content
‫that we actually want to display inside the modal.
‫So basically we want some button to open the modal,
‫and we want the window itself.
‫So these two components together should form
‫the modal component.
‫And if this sounds a lot like
‫the compound component pattern, that is because, in fact,
‫a compound component is perfect for a situation like this.
‫And so we will now, as I just mentioned,
‫implement this whole modal using a compound component.
‫So let's comment all of this out
‫so that we still keep that code as a reference.
‫And so let's create a new component here.
‫And then let's start by basically creating the API
‫of this component.
‫And so then we will know what we should actually implement.
‫So we want, again, a modal component,
‫so just like before.
‫And then in there, let's say we want that button,
‫and a button to open this.
‫So Modal Open, and then the window itself.
‫So let's call this one Modal.Open.
‫And so it's gonna be into this window
‫where we are going to place the content itself.
‫So in this case, that's CreateCabinForm.
‫And then here into this Modal.Open,
‫we want the user of this component
‫to be able to pass in the button itself.
‫So of course we could make this Open itself also a button,
‫but then we would lose a bit of the flexibility
‫of the component, 'cause then we would have to define
‫the style and so on.
‫And so instead, let's allow the user to pass in
‫whatever button they want.
‫And so let's again use our primary button here,
‫and then Add new cabin.
‫All right, now of course, this will create some errors
‫because we didn't implement any of this yet,
‫but, well, let's just keep going.
‫So this is already looking like a real nice API.
‫And if you ask me, a lot nicer
‫than what we actually have here.
‫So now we have no more state needed here
‫inside this AddCabin component.
‫And instead we will keep that state
‫whether the window is open or not right inside the modal.
‫Now just one more thing, which is that we actually want
‫to allow multiple windows.
‫So let's say, for example, we also want one to show a table.
‫So we can then do this.
‫So we have another button to open and another window.
‫So we want the user of the modal component
‫to be able to do this,
‫so basically having multiple modal windows.
‫However, of course, only one of them
‫can be open at the same time.
‫And so therefore each of these buttons
‫needs to know which window it should actually open.
‫And so therefore here, let's pass an prop called opens.
‫And let's say this one opens the cabin form.
‫And so then we simply give this window here
‫exactly this name.
‫So let's give this one the name prop
‫and then call it cabin form.
‫All right, and then here, well,
‫let's already pass in some different prop here.
‫Let's say table, and then we call this window here table.
‫Alright, and then here, well, let's do this later.
‫So let's comment this one out for now.
‫So this was just to show you
‫that we can have multiple windows
‫inside the same modal component.
‫And so since we have that additional flexibility,
‫then we need to give each window a name.
‫And then we associate each open component here
‫to that name now.
‫All right, and as we also just mentioned,
‫then the modal basically needs to keep track
‫which one is currently open.
‫And so let's now go implement all of this here in our modal.
‫And let's duplicate this file first,
‫so that you can also keep the original one.
‫And then let's go here.
‫And so now we are going to follow
‫the same four steps that we did previously
‫in order to implement a compound component.
‫And the first one is to create a new context.
‫So ModalContext,
‫let's say createContext from React.
‫And so that is the first step.
‫Then next step is to create the parent component.
‫So that's what we have here.
‫So that's already called Modal,
‫but let's actually call it here Window,
‫'cause the window is what will actually contain this portal
‫and all this JSX here.
‫All right, and so then let's create the parent component,
‫which is the modal itself.
‫And this one also needs to accept children
‫so that then it can display the Windows and the Opens.
‫Now, okay, and then here is where we will keep track
‫of which is the currently open window.
‫So let's call that the openName and setOpenName.
‫So then of course we use a useState hook for that,
‫and we start with no empty window,
‫and therefore we just use as a default here
‫an empty string.
‫Then next, let's also immediately create
‫the handler functions.
‫So let's say close is equal.
‫So closing a modal or a modal window
‫is as easy as simply setting the openName
‫back to the empty string.
‫So this function all it will do is setOpenName
‫back to nothing.
‫And the opposite is to open a window.
‫And opening a window is just the same thing
‫as setting the openName.
‫So let's just rename that here.
‫So this is a bit more explicit what is happening,
‫but basically opening is simply setting this openName
‫for example, to cabin form.
‫And so then this window that has this name
‫will be displayed.
‫All right, and so we already have that window.
‫Let's create the button itself,
‫or actually the Open.
‫So this accepts the children, and as we we saw earlier,
‫also the Opens prop while this one accepts the name prop.
‫And the onClose we will remove in a minute.
‫All right, and before we keep going,
‫let's implement the last step as well,
‫which is to place these two S properties on the modal.
‫So Modal.Open is Open,
‫and then Modal.Window is just Window.
‫All right, and so now let's get to work implementing these.
‫So first of all, in the Open component,
‫we will need access to the open function from the context.
‫So useContext with ModalContext.
‫And so now here we want to then return
‫whatever we pass in here, right?
‫So in our example, we passed in this button.
‫And so then we want to return this button
‫from this open modal.
‫However, how do we now actually add the open event handler
‫to this button?
‫I mean, of course we cannot do it right here
‫because here we don't have access to any
‫of the internal state
‫and these state updating functions, right?
‫And that's actually the whole point
‫of having the API design like this.
‫So if we're having a component that we use in this way,
‫and so we need to solve this problem.
‫So again, what we need to do is now a way
‫of adding that open event handler to this button,
‫so to the children prop of open.
‫So basically adding this function here to the children.
‫And the way we can do this is by using
‫a pretty advanced React function called cloneElement.
‫And to learn more about this function,
‫let's actually head over to the React documentation.
‫So I think we haven't checked this out
‫since the beginning of this entire course,
‫but I think it's still interesting
‫to now look up this function.
‫So cloneElement. Let's wait for it here.
‫Seems like my internet connection
‫is pretty slow at the moment.
‫Ah, but here it is.
‫So first of all, here we see that cloneElement
‫is pretty uncommon.
‫And so one thing that's important to mention here
‫is that you should not overuse the technique
‫that we are going to implement here soon.
‫But anyway, this technique can still be pretty useful
‫because the clone elements basically allows us
‫to create a new React element based on another one.
‫So we in the element, and then we can pass in props,
‫which will solve our problem here in our case.
‫And it's the reason why we're going to use this.
‫So instead of children, we will clone the children.
‫So we will basically create a new version
‫of the children but with new props.
‫And so those props will contain the onClick prop.
‫And then this onClick prop will become a function
‫that actually opens a modal window.
‫So this function will then call open with the opens prop.
‫So let's actually maybe change this here
‫to make it a bit more explicit.
‫So opensWindowName.
‫All right, and this is actually it.
‫So since we cannot place that function directly here,
‫what we do is to clone it.
‫So we clone that button, and then, as props,
‫we pass in the onClick prop as always
‫when we need to handle an event.
‫And then the event handler function
‫is simply to open the window with this name,
‫so with the name that we have here as a prop.
‫So this case, the cabin form, right?
‫And so now on the window we basically need to check
‫which is the currently open window.
‫And if it's the same as this name,
‫then we want to render its content.
‫So let's just do that, so what I just explained.
‫So basically if the name here is different
‫from the openName, which we will soon get from the context,
‫then don't return anything.
‫Then just return null.
‫But if the name is equal to the currently open window,
‫then, well, then we return this.
‫All right, and so now let's grab the openName
‫and also the close function from the context.
‫So useContext with ModalContext,
‫and then we can finally get rid of this onClose prop
‫because, again, earlier this was actually coming
‫from the outside.
‫So the only way in which we would close a modal
‫would be here with this function.
‫And so that was necessary
‫because the state was living outside of the modal.
‫So using this function right here,
‫but since that is no longer the case now,
‫we, of course, no longer pass this in.
‫And instead we use our internal close function,
‫so the one that we get from the context.
‫And so I believe with this, we are actually done
‫at least with the basic functionality.
‫So let's check this here, reload.
‫And now for some reason, our button isn't there.
‫So ah, of course not.
‫So I forgot one of the most important parts,
‫which is to even return something from this modal component.
‫And so then of course all the children
‫couldn't even be shown here.
‫So of course we need now the ModalContext.Provider
‫with the value of the openName,
‫the close and the open functions.
‫And then in here we want to pass in and render the children.
‫And so there we go.
‫So let's close this.
‫And now as we click here, beautiful.
‫It does open our modal.
‫So it works exactly the same way as before,
‫but now we have this as a compound component.
‫Nice.
‫Now maybe you notice that the styling is again off.
‫And the reason for that is that the styling here
‫is only applied with the type of modal
‫when this component here receives a function.
‫So let's just quickly review that
‫because this is pretty important.
‫So it is this one right here.
‫And so remember that earlier we passed
‫the onClose modal function into this form.
‫And so if that existed, then here the type
‫of the form would be a modal form.
‫So right now that is not showing up here
‫because we are indeed not passing in
‫the onClose modal function yet.
‫And so let's change that.
‫So right here in our modal is where we will have to pass
‫in that function because, again,
‫we can no longer pass it in here.
‫So that's what we did earlier.
‫We passed that function here, but again,
‫now we do not have that function out here,
‫which is actually great, but now that means
‫that we need to pass it in in another way.
‫And the way we will do that
‫is exactly with the same technique as here.
‫So we will grab this children and clone it.
‫So clone the children, and then we pass in again props.
‫And this time the name of the prop is called
‫onCloseModal, and we just set it to the close function.
‫And there we go.
‫So immediately you saw that the styling had changed.
‫And now we can also close the modal by clicking
‫on this button and also by submitting here in new cabin.
‫Beautiful. So it's working really great.
‫Let's now just only, or also activate this one.
‫So here we want to then display the CabinTable.
‫So just to see.
‫So indeed we get another button,
‫and this one here has this prop.
‫And so therefore now, as we click this button here,
‫the openName will become table, right?
‫So that's the opens prop right here.
‫And therefore if we click the button here,
‫then the opens function will get called,
‫and then that will set table right here
‫to this openName.
‫Okay, and then here in our windows,
‫one of the two windows will then have the name
‫equal to table, and so that one will then no longer
‫return null but will instead return our window.
‫And beautiful. Great.
‫So here we now get our table,
‫and here we get our cabin form.
‫Very nice.
‫And with this, actually our work here is done.
‫So I hope that this new implementation of the modal
‫using the compound component pattern made sense to you.
‫Now, the main focus here is really
‫on how to use this very important pattern.
‫So don't focus too much
‫on the specific implementation details
‫of this specific modal component.
‫So when you use this compound component pattern
‫in the future to maybe build your own components,
‫then those won't be maybe modal components.
‫And so really what I want you to retain the most
‫from this lecture is really how we can use
‫these different basically child components
‫to together achieve a goal.
‫So in this case, displaying a modal window.
‫And it's always in the same way.
‫So we have some state and some state updating functions
‫here in the parent component.
‫Then we pass that with a context,
‫and then in the child components,
‫we use those to achieve the goal
‫of displaying a modal window in this case.
‫So I want you to study this pattern here a little bit more,
‫maybe review all the code that we wrote.
‫You can also check out the component tree as always,
‫because it's actually pretty interesting in this case.
‫For example, the fact that we do indeed
‫have all the windows already in our component tree.
‫So here we have the one with the table
‫and the one with cabin form.
‫So they are actually rendered,
‫but they are not rendering anything.
‫So they only start rendering something
‫when this name here is equal to the openName State here.
‫So this one.
‫So if we change this to table,
‫then indeed the table modal window will show up.
‫All right, then also review maybe this technique here,
‫and you can think of a few other use cases maybe,
‫and also read again the documentation.
‫And then once you're done with all that,
‫so really understanding what we did here,
‫let's move on to the next lecture
‫where we will implement one final missing detail
‫of this modal window.