‫Let's now implement a new small feature
‫which will require us to listen globally
‫to a keypress event.
‫So let's check out what that feature is in our demo.
‫And so basically it's very simple.
‫When we open up a movie here to see the details,
‫instead of clicking here on this button to go back,
‫we want to now implement a feature
‫that the user can also just click on the Escape key.
‫So you can't see that,
‫but I'm doing it now.
‫And so with this,
‫the movie detail was then closed.
‫And so again, for that,
‫we basically need to globally listen to that keypress event.
‫So let's get to work.
‫And the way in which we can react
‫to a keypress event in the entire app
‫is basically by simply attaching an event listener
‫to the entire document.
‫So let's do that here, right in the App component.
‫And so since this is clearly a side effect
‫because we will be directly touching the DOM,
‫we need another effect.
‫So just to show you that we are indeed in the App component.
‫And so let's create that effect right here.
‫So useEffect,
‫then our effect function,
‫and then as always,
‫we start by saying basically
‫that this effect should run on mount.
‫And so now all we need to do
‫is to write document.addEventListener,
‫which, remember, is simply a DOM function,
‫so we are really doing basically now some DOM manipulation.
‫And so we are stepping really outside of React here,
‫which is the reason why the React team
‫also calls the useEffect hook here an escape hatch.
‫So basically a way of escaping
‫having to write all the code using the React way.
‫Okay.
‫But anyway, here let's now listen for the keydown event,
‫and then as our callback function here,
‫we just pass in a function
‫which receives the event.
‫And now we can simply say if the event.code,
‫which is basically the code of the keypress,
‫so if that is equal Escape,
‫then we will want to call our handleCloseMovie function.
‫So we already have that functionality
‫and so all we have to do
‫is to call that function right here.
‫And let's also just, for some experiment,
‫log something to the console.
‫So just like this.
‫And let's reload here,
‫but let's first actually come back to our network
‫and disable any throttling.
‫So let's reload,
‫then let's open up a movie,
‫and then let's see what happens when I hit the Escape key.
‫And indeed, the movie here was closed
‫and we also got our closing logged to the console.
‫But watch what happens right now
‫as I hit the Escape key again.
‫So you see we get closing again,
‫and actually even twice.
‫But again, that's simply because in strict mode
‫these effects here are running twice.
‫So again, as I keep hitting the Escape key,
‫we see here by this log
‫that actually this callback function here,
‫so the event listener,
‫is still listening for the keydown event
‫and it will then execute this function
‫each time that the keypress happens,
‫which is, however, not really what we want in this situation
‫because we actually don't even have a movie opened here.
‫So basically what we want instead
‫is to only attach this event listener here to the document
‫whenever we actually have the movie details in our tree,
‫so whenever that component instance is actually mounted.
‫So that's easy enough,
‫we just cut the effect from here.
‫And so after all,
‫we want it in our MovieDetails component.
‫All right.
‫I just started to place it there
‫so that we could understand why we actually need it here.
‫And now here, of course,
‫this function is called onCloseMovie,
‫which, again, we had already passed
‫into this component right here.
‫Now, here you see that actually ESLint is complaining
‫and the reason for that
‫is that we must actually include this function here
‫also in our dependency array.
‫So that doesn't seem to make a lot of sense,
‫but we will later learn why that is.
‫So again, when React tells us
‫that we need to include something here in the array,
‫we actually must do that.
‫Otherwise, there might be some consequences
‫that we do not want.
‫And so, again, whenever you see some warning here
‫coming from ESLint about a missing dependency,
‫you must include that in the array.
‫So otherwise, React says that you are lying
‫about your dependencies
‫and that, of course, we don't want.
‫But anyway,
‫let's not try to hit the Escape key again
‫while the MovieDetails component is not mounted.
‫And so now we didn't get that console.log,
‫and so therefore, now this function is, of course,
‫not being executed.
‫But as I open up the movie and then I hit the key again,
‫then you see that we get the closing log,
‫and of course, the movie has closed.
‫Okay, let's do that again.
‫And notice how now we are getting even more
‫of these logs here.
‫And let's clean that and do that again,
‫and a few more times.
‫And so you see that we get dozens of these logs here
‫saying closing,
‫which don't really seem to make much sense.
‫So if we reload the page and then do that again,
‫then we are back to only having these two logs,
‫which again, come because the effect is executed twice.
‫But now if I close another movie,
‫then all of a sudden we get three logs.
‫And so it seems
‫like these are basically accumulating, right?
‫So the reason for that is that, actually,
‫each time that a new MovieDetails component mounts,
‫a new event listener is added to the document,
‫so basically always an additional one
‫to the ones that we already have.
‫So again, each time that this effect here is executed,
‫it'll basically add one more event listener to the document.
‫And so if we open up 10 movies and then close them all,
‫we will end up with 10 of the same event listeners
‫attached to the document,
‫which, of course, is not what we want.
‫And so what this means
‫is that here we also need to clean up our event listeners,
‫or in other words, we need to return a function here
‫which will call
‫or which will execute document.removeEventListener.
‫So basically,
‫as soon as the MovieDetails component unmounts,
‫the event listener will then, again, be removed
‫from the document,
‫and so then we will avoid having so many event listeners
‫in our DOM,
‫which might become a memory problem in a larger application
‫with hundreds or thousands of event listeners.
‫So again, in this small app, of course,
‫this wouldn't be a problem,
‫but this is just to teach you,
‫so to prepare you for the real life later.
‫Now here, the function that we pass in,
‫so the one that we want to remove,
‫must be exactly the same as here in the addEventListener.
‫And so we cannot simply copy and paste
‫this function right here.
‫So it must be, again, the same.
‫And so let's cut it from here
‫and create a brand-new function here.
‫Let's just give it a name of callback.
‫And then let's use that here and here.
‫Give it a save.
‫Let's reload here.
‫Okay.
‫I hit Escape.
‫And let's try it a couple more times.
‫And you see that now we only get one closing
‫each time that I hit the Escape key,
‫or in other words,
‫actually our event listener is only executed exactly once,
‫which was exactly the goal of our cleanup function here.
‫Great.
‫So this is how we handle keypress events
‫in a React application.
‫So again, we need to basically step out of the React way
‫and back into classical DOM stuff.
‫And so for that, we need an effect.
‫So we specify our effect,
‫we listen for the event,
‫and each time that the component unmounts,
‫or even each time that it re-renders,
‫we will then remove the old event listener
‫from the document.
‫All right.
‫And this is actually going to be the last lecture
‫of this section.
‫And so let's clean up the application here a little bit
‫before we leave this section,
‫even though we will actually keep working on it
‫in the next one,
‫but still, let's do some stuff here now,
‫which is to, for example, remove all of these redundant
‫and unnecessary console.logs.
‫We also have some other cleanup here like this.
‫So this one we don't need,
‫but maybe let's just comment this one out
‫because this was nice for the explanation of the closure,
‫remember?
‫And then, of course, also when we open up the app,
‫of course we don't want to display search results
‫for a predefined movie,
‫so in this case for the "Inception" movie.
‫So let's remove that from state
‫and simply start with no search term at all.
‫All right.
‫Then here we should probably not log these errors
‫here as console.error,
‫but as a console.log.
‫And also when the error is an abort error,
‫we don't even need to log anything
‫because, again, for us,
‫those are actually not really errors.
‫And finally, let's now search for a movie here.
‫So "Interstellar", for example.
‫All right.
‫So I selected the movie
‫and now let's say that I search for something else.
‫And so in this situation,
‫I think that it would be best
‫to close the current movie here.
‫So whenever there is a new search,
‫we simply want to close the movie.
‫And so that's pretty simple.
‫We just have to, before we fetch the movie,
‫simply call handleCloseMovie.
‫And so with this,
‫let's see.
‫So we open up this one and then let's search.
‫Let's see what actually turns up for Jonas.
‫Something about the Jonas Brothers.
‫Yeah, but anyway,
‫you saw that as I did a new search,
‫then the movie here actually disappeared,
‫and the same now again.
‫Okay.
‫Now, as we load the application right now,
‫so on the initial render of the entire app,
‫we notice that right now we are no longer fetching any data,
‫right?
‫So we are only fetching data as a result
‫of searching here for movies in the search bar,
‫so basically only as a response to this event.
‫And so therefore,
‫we could now actually transform
‫this useEffect that we have here
‫into a regular event handler function,
‫because remember, that is actually the preferred way
‫of handling events in React.
‫And again, this is actually now more of an event handler
‫than anything else, right?
‫So again, if you think about that,
‫then maybe you come to the same conclusion
‫that maybe this shouldn't be an effect anymore
‫and really an event handler function.
‫So if you want,
‫you can go ahead and convert that,
‫but it's also not really necessary
‫because the main point of this section here was to learn
‫about the useEffect hook.
‫And in many situations,
‫we do actually want to start fetching on mount.
‫And so in those situations,
‫this is still a perfectly valid way of doing that,
‫at least in small applications like this one.
‫But anyway, with this,
‫we wrap up the section,
‫and so now all there's left to do is, as always,
‫a nice coding challenge
‫so that you can practice on your own.