‫Welcome to the last lecture of this project.
‫And in this one we're going to use our old friend
‫use effect to implement a timer feature.
‫And this new feature will play really nicely
‫with the reducer that we already have.
‫So when the game is going to start
‫the timer will also start, and once the timer reaches zero
‫we will have the game stop
‫by setting the status to finished again.
‫So we will be able to model this behavior really beautifully
‫with our reducer.
‫So let's start by creating a timer component
‫which will display the current time that is remaining
‫and that will actually also start the timer
‫in the beginning.
‫So that component should be right here at the bottom.
‫So I mean at the bottom here of our UI
‫so basically down here besides this button.
‫So what we want is actually for these two components
‫to be inside a footer.
‫So we will want a timer,
‫so the component that we will build next.
‫And then we want,
‫again these two inside a footer HTML element.
‫Now this is ugly like this, so as you already know
‫I really don't like to see it this way.
‫And so let's just quickly create ourselves
‫a footer component.
‫And so all this will do is to return a footer element
‫which will then contain the children that we pass in.
‫Alright, so doing some more component composition here.
‫And of course we could also just call both the timer
‫and the next button in here,
‫but then we would have to pass all the props in here
‫just to then pass them into these other components.
‫And so that's not really necessary.
‫So footer.
‫And let's also create the timer immediately here.
‫And then let's just return the timer string for now
‫so that we can then include so import these two components
‫into our application here.
‫So the timer and the footer.
‫So that's all the components we are going to build.
‫And as you see, there are a lot of them,
‫so I like to keep them a bit separated
‫from the other imports.
‫But anyway, let's now see what we get.
‫And so here we have our timer basically.
‫So it's not really a timer yet
‫but so let's now change that.
‫So first of all, it needs the class of timer.
‫And then let's pretend that here we have just some time
‫so just so we can see something.
‫So this already looks a bit nicer.
‫Now okay, and so here, let's now again use
‫the useEffect hook to create a side effect on mount.
‫So as this component here mounts
‫we basically want to initialize the timer
‫and we are doing that right here.
‫So we are starting the timer here in this component
‫because this timer component will mount
‫as soon as the game starts.
‫So of course we couldn't start the timer
‫in the app component here
‫because then the timer will start running
‫as soon as the entire application mounts
‫but that's not what we want.
‫So we have to place this effect
‫into one of the components that mounts as the game starts.
‫I mean there would of course be ways around that
‫but I think it makes just sense also
‫that this effect is here in this timer component.
‫But anyway, how do we actually create a timer in JavaScript?
‫Well, first of all, this of course
‫needs to be a function here
‫but then we will now use the set interval function.
‫And so this function will simply run
‫the function that we pass in here,
‫every couple of milliseconds which we can also define.
‫So let's pass in our function,
‫which could also be an arrow function here by the way,
‫but let's just do it like this.
‫So for now, we want to lock to the console
‫the string of tick once per second.
‫And so that's every 1000 milliseconds.
‫Now this will already have started a timer now.
‫So if we come here to the console,
‫then you see that every second
‫while now we actually get two ticks here.
‫But that's again because the effects run twice
‫in development mode.
‫So this wouldn't be happening in production
‫but now it does.
‫But of course what we want to do here
‫is not to lock something to the console,
‫but instead we want now some value.
‫So we will want some state value
‫that we can then decrease every second.
‫So let's take out this console dot lock here for now
‫and reload our page so that we don't create
‫any additional work for the page.
‫And then let's come here again to our state
‫and add one final piece of state.
‫And so that is going to be the seconds remaining.
‫And we could do it also the other way around.
‫So we could start at zero and then add one every second
‫until we reach a certain number.
‫But here instead we will start at some number.
‫So for now, let's just say 10 seconds
‫and then we will remove one second every second.
‫And once that reaches zero
‫so once there are no more seconds remaining
‫then we will finish the game.
‫So let's now implement what I explained.
‫And so once again
‫we will just leverage our reducer here again.
‫And add one final event here
‫and this one I'm going to call it tick.
‫So because like a clock, this will happen every second.
‫So this is the event that we are going to dispatch
‫here in this function.
‫And why not actually do it immediately here
‫since we are already here?
‫Let's dispatch the event with the type of tick.
‫Then we need to give this access to the dispatch function.
‫Interior is not dispatch event.
‫And now VS Code is complaining
‫or actually ESLint because dispatch is now a dependency.
‫So let's edit then if React needs it.
‫And so now of course, don't forget to pass it in,
‫not like we did in the previous lecture.
‫And now we are ready to model here
‫our state transition again.
‫So we want all the state,
‫and then we want seconds remaining
‫to be equals state dot second remaining minus one.
‫So as I said a minute ago
‫we will simply subtract one second every second.
‫And now let's also pass that into the timer
‫so that it can display this value.
‫So seconds remaining here, taking it out of the state
‫and then seconds remaining here.
‫And then of course
‫we also need to accept that as a prop here.
‫And yeah, then place that right here.
‫And with this we should be good to go.
‫So let's see.
‫And yeah, that's working great.
‫Now of course for now we are still allowing this
‫to go below zero and so let's fix that next.
‫So basically we now want to check every second
‫if this has reached zero,
‫and if it has then we will finish our game.
‫So exactly like we have been saying in the very beginning.
‫So this feature fits now really, really nicely
‫into the entire state structure that we already have.
‫So we can just now use again the status
‫and then we can check if state dot seconds remaining
‫is equal zero.
‫And if it is, then here we return finished
‫and otherwise it just stays the same.
‫So that's then state dot status again.
‫So this right here is the entire heart of this feature.
‫So basically allowing us to check
‫if the seconds came to zero.
‫And so if they did reach zero
‫then we just set our status to finished
‫which will then trigger the entire game to stop
‫and to then of course render this finished screen
‫instead of what we have here in the active state.
‫So let's reload.
‫And let's see.
‫So that's why we used a small number
‫so that we can see immediately if this works
‫and it does, great.
‫And even if we restart the quiz
‫then it starts again at the value that we had before.
‫So that is because here when we restart
‫we just took the entire initial state here again.
‫Remember that, but maybe you notice something here
‫when we restart the quiz.
‫So let's try that again and see how fast this goes now.
‫And if we do, again, it will be even faster.
‫Actually, we don't even have to start a quiz
‫that this moves now to the finish screen.
‫So clearly something is going wrong,
‫so notice how fast this goes.
‫And the reason for that
‫is that our timer actually does never stop right now.
‫So we have no cleanup function.
‫And so therefore our timer here
‫will keep running even after this component has unmounted.
‫So that of course, we need to fix.
‫And so this is an amazing use case for the cleanup function.
‫So what we need to do is to store the idea of the timer
‫that gets returned from this method.
‫And so we can then use it in the cleanup function
‫that we return from here.
‫So to clear an interval,
‫we basically just have to pass in the ID
‫of the timer that we started with set interval.
‫So every single set interval timer will return a unique ID.
‫And so we can then again use that to clear,
‫so to cancel that timer.
‫And so now this will run between renders
‫and even more importantly
‫after this component is unmounted
‫and so then the timer will really actually stop.
‫So what we had before
‫was that each time we restarted our quiz,
‫a new timer got added.
‫And so then we had many timers running at the same time
‫which were all dispatching this action.
‫And so then our time was going down
‫really really fast because of that,
‫but this should fix it.
‫So let's try that.
‫And actually now we are only going down
‫one second at a time.
‫And there we go.
‫So that was expected, but now let's see again
‫if the timer has the same speed as before,
‫and yeah, it does.
‫And so it means that this cleanup function here
‫is indeed working.
‫Now notice how here we are getting all of these renders
‫or actually all of these console logs
‫and that's because of course now the entire application
‫so all the components will re-render every single second.
‫So let's just quickly review what we learned before
‫and that is that as one component re-renders
‫all its child components will re-render as well.
‫So our state lives here in this global app component
‫and so therefore as our state re-renders
‫so will re-render all of these child components.
‫And so that is of course also true
‫here for the question component that does this render here
‫which will then create this lock here every single second.
‫So let's just quickly clean that up right here.
‫And so this could become a performance issue
‫in a really large application
‫with like a thousand components.
‫So in that case, you probably shouldn't have
‫your most parent component re-rendering every single second.
‫But in this case, this is really not a problem.
‫Now, of course, our 10 seconds that we have here
‫are not nearly enough, right?
‫And so what we want to do now
‫is to calculate the amount of seconds
‫from the number of questions that we have.
‫So let's do that.
‫So our seconds remaining start at 10,
‫but again we want to know,
‫calculate it from the number of questions.
‫However, we don't know that number
‫at the very beginning, right?
‫And so let's just set this to null
‫and instead calculate this number here as we start the game.
‫So at this point when this action is dispatched
‫we will already have the questions array.
‫And so then here we can calculate those seconds remaining.
‫So let's say state dot questions dot length,
‫so the amount of questions
‫and then maybe 30 seconds per question.
‫Now, we shouldn't actually place
‫like a magic number like this here.
‫So instead we should always create a constant out there
‫for a value like this.
‫Otherwise it will be really weird
‫and unclear to suddenly see a 30 in here.
‫So let's create a constant
‫that will be called seconds per question,
‫and it's kind of a convention to have these upper case.
‫So secs per question equals 30.
‫Okay? ‫So that should work now.
‫And yeah, now we have plenty of time I think
‫to complete the quiz, which again, I hope you will do
‫or maybe you already have done
‫here outside of one of these videos.
‫But now to finish, let's then also form at this
‫a little bit nicer.
‫So for example, separating the minutes from the seconds.
‫So let's create a minutes variable here.
‫So let's do math dot floor.
‫And so then we just divide the seconds by 60.
‫And so this here will give us the amount of minutes
‫and then we round that down with math dot floor
‫so that we can then, besides the minutes,
‫also display the seconds.
‫And so this will be seconds remaining,
‫and then the reminder of dividing that by 60.
‫So that's again, just pretty standard stuff.
‫And then here, let's display that.
‫So minutes and seconds,
‫give it a save.
‫And now this doesn't look really nice
‫because ideally we also want like trailing zero there
‫in some situations.
‫So not now, but if it is less than 10,
‫but that's pretty easy as well.
‫So minutes less than 10,
‫and if so then just place a zero there.
‫And so there it is.
‫And well then the same thing for the seconds.
‫So seconds.
‫And right now that's not the case,
‫but we will maybe see it in a second
‫or in a in 20 seconds, actually.
‫But yeah, we probably don't have to wait for that
‫because actually with this we finished our application
‫so it's feature complete.
‫Now the only thing that we might do is to fix our title.
‫So let's come here and call this,
‫"The React Quiz."
‫And there it is. ‫Beautiful.
‫And now we really are finished with this application.
‫So congratulations, you just added
‫one more really nice React application to your portfolio.
‫So I hope this was a fun one.
‫I sure really liked to develop this one with you.
‫So we learned a lot about reducers and to useReducer Hook,
‫but also, again we learned some more
‫about React development in general.
‫And you could take this project even further if you wanted.
‫So I have at least three ideas
‫for features that could be implemented.
‫So first of all, in the start screen right here
‫we could do different kinds of stuff.
‫For example allowing the user
‫to only select a certain number of questions,
‫or also to allow the user to filter
‫for the difficulty of questions.
‫Now, another thing that we could do
‫is to upload the high score of the quiz
‫to our fake API as well.
‫And then as we reload the application later
‫that could then re fetch the high score
‫and place it back in our state
‫so that we don't lose that value.
‫And finally, another idea that I had
‫is that we could store all the answers
‫here in some array instead of just the current answer
‫like we do right now.
‫And so by doing that,
‫the user could then go back and forth in time
‫and review their answers like that.
‫So if you want you can have some more fun with this project,
‫and if you do please make sure to share some GitHub link
‫or something like that, or maybe just the final application
‫in the Q and A of this lecture.
‫And so now to finish this section
‫we will quickly review what we learned
‫about useReducer and compare it with the useState Hook.
‫So see you there soon.