‫In this video, we're gonna play a sound
‫whenever the duration state changes.
‫And this will bring up all kinds of interesting issues
‫that we are gonna solve using
‫the strategies that we have learned
‫in the advanced useEffect lecture earlier.
‫And I already created this function here
‫to play a certain sound and I think it's pretty interesting.
‫So what we have to do is to first import a sound file.
‫So like this one that is here in the source folder.
‫So we import that then store it into some variable,
‫and then we can use that using
‫the audio API from the browser.
‫So this is here just a browser feature.
‫So this then creates a new audio, which I just called sound.
‫And then on that we can call the play method.
‫And so now let's use this function
‫in order to play this sound
‫each time that the duration updates.
‫So where does that actually happen?
‫So where does the duration update?
‫Well, easy enough.
‫Here in these two handler functions and in this effect.
‫And so let's just play or actually call
‫that function in all those places.
‫So here and here.
‫So in the two event handlers
‫and let's already test if this works.
‫And yeah, I can very clearly hear
‫that sound in my headphones.
‫So it's not in the video because of my headphones,
‫but you should probably also hear it.
‫Now if you do not want that sound
‫maybe because you need to be in silence or something,
‫then you have this icon right here.
‫So this is coming from the toggle sounds component.
‫And so when you click here,
‫it will set the allowSound state to false.
‫And so then in this case, the sound is not played.
‫So then it goes just back to normal.
‫But here for the sake of this exercise,
‫let's leave it on and see that it works just fine.
‫But of course, as we change the duration here
‫that will not yet play the sound.
‫And so let's also place that here.
‫But now this play sound is actually a reactive value
‫because it uses another reactive value.
‫So this allows sound prop, so it is actually a prop,
‫but we see that it is a prop that is actually state.
‫So that allowSound prop is a state variable
‫and therefore it is a reactive value.
‫And so this function is then also a reactive value
‫and then we need to place it right here.
‫So playSound like this.
‫Now here since we are using
‫not a normal function declaration, function expression,
‫we need to place it here before.
‫And so now it is back to working.
‫Now notice how here in the console we get these issues,
‫which tells us that a sound cannot be played
‫before the user interacts with the document.
‫So the user first need to click or really do
‫something here before the first sound can be played.
‫But let's just ignore this issue here in the situation.
‫So we placed our playSound function here
‫in the dependency array in order not to lie
‫to React about the dependencies.
‫But watch the problem that this actually creates.
‫So as I try to update the state here now
‫as I click here nothing really happens.
‫I mean, we hear the sound like playing twice
‫and very shortly it goes up and then goes down again.
‫So you see this flicker here.
‫And so that is a big problem.
‫The same thing probably appears here.
‫Now here it actually works fine
‫but not when we click on these buttons.
‫So let's find out what the problem here is.
‫So each time that we click here on this button,
‫it will set the duration and it will play the sound.
‫Now updating the state will
‫of course re-render the component,
‫which will recreate this function here.
‫So React will see a brand new function.
‫And since this function is part of the dependency array
‫of this effect, it will then run this effect as well.
‫And so that's where the duration is
‫then set again but using the current values,
‫which actually haven't changed.
‫So when we click here, none of these four values changes.
‫And so when the duration is then set here
‫for the second time, it will use these values again,
‫which will make it so that the duration
‫immediately goes back.
‫And so that's why we see that flashing.
‫So for a fraction of a second it'll go to 53,
‫but then immediately it'll go back.
‫So saw that here.
‫So that is the reason why this is happening
‫and also why we kind of hear the sound twice.
‫So we hear it here
‫and we then hear it again from this effect.
‫So what can we do?
‫Well, as we learned in that lecture about the strategies
‫on how to deal with helper functions, which this clearly is,
‫there is a few things that we can do.
‫So the best strategy is always to move
‫a function like this out of the component.
‫However, that doesn't work because this function is
‫of course a reactive value that depends on this prop
‫and so we cannot move it outside.
‫Then the other strategy would be to take
‫the function and move it into the useEffect.
‫So right into here.
‫But then the problem with that would be
‫that we could no longer use it out here.
‫And so this is the situation where we need
‫that function in multiple places.
‫And so then what we have to do is to memorize the function.
‫And so then the function will not be recreated
‫between these renders.
‫So let's do that, useCallback.
‫And then here in the dependency array
‫what do you think we will need to place there?
‫Well, we will need for sure this allowSound variable
‫because this is a reactive value.
‫So a value that can change over time.
‫But what about this click sound?
‫Well, this one, not really.
‫So this is never gonna change and React knows that.
‫And therefore if we now save this, we get no warnings.
‫So meaning that our dependency array is complete.
‫And so if we try this now again,
‫then it is actually back to working.
‫And it does work everywhere.
‫Nice, so yet another use case of the useCallback hook.
‫Now one very interesting consequence is
‫that now as we click on this button
‫so on this icon right here, it will actually play a sound.
‫So did you hear that?
‫Not when we turn it off.
‫But when we turn it back on, it will play a sound.
‫So that's a bit strange, right?
‫So why is that happening?
‫Well, notice how here allowSound is in the dependency array
‫of useCallback, which means that this function here
‫actually does get recreated each time
‫that allowSound changes.
‫Therefore when we toggle this icon here
‫we get a new function,
‫which then in turn will make this effect here run again.
‫And so that's where then the sound is played.
‫So this can quickly become confusing when you use
‫all these useCallbacks and useEffects in your code.
‫And let's see how this actually becomes even worse.
‫Because let me now update the state here a little bit,
‫and then watch what happens when I click here.
‫So you saw that it basically reset our state.
‫So very strange, very confusing probably.
‫But again, it is actually for the exact same reason
‫that earlier we heard the sound when we click here.
‫So the reason for that is once again,
‫that whenever we click on that icon
‫the allowSound state changes
‫and so then the function is recreated.
‫So then on that update, React sees a new function.
‫And since that function is here in the dependency array,
‫it will run this effect again.
‫And so this effect will run with the current values
‫of these four pieces of state.
‫And so it will recalculate the duration based on that.
‫Basically ignoring that earlier we had manually changed
‫the duration with these buttons.
‫So of course, I did all this on purpose.
‫So I created this kind of sophisticated example
‫to show you all these consequences
‫that these hooks can have in our code.
‫Just so I could show you the thought process
‫behind analyzing what happens here so that you can
‫in the future think about this stuff on your own.
‫So I think that this is really, really important
‫and will make you a better React developer for sure.
‫Now, the solution for this problem is
‫to do something completely different.
‫So instead of using useCallback here
‫and instead of playing the sound here and here,
‫we can do something entirely different.
‫So let's think about this.
‫When do we actually want the sound to play?
‫We want it to play whenever the duration changes.
‫So that's why we placed this function in these three places.
‫However, as I just said, there is a better way of doing that
‫and one that is way more clear and more intentional,
‫which is to simply synchronize this side effect
‫of playing the sound with the duration state.
‫So instead of all this that we just did is
‫to create a new separate effect
‫which will be responsible for playing the sound.
‫So basically for keeping the sound synchronized
‫with the duration state.
‫And now thanks to this,
‫so now that we no longer need this function right here
‫we can take the function,
‫but let me comment it out and leave it here for you.
‫But we can now take this function
‫and un-comment it and remove the useCallback
‫of course and what's this?
‫(stutters pensively)
‫Ah, it's function not whatever I had there earlier.
‫So anyway now we can remove play sound from all of here,
‫remove this of course from the dependency array,
‫which is what we wanted all along.
‫And then remove it from here as well.
‫So take all of that away.
‫And so now here is where we want to call that function.
‫And so again, this time we were able
‫to finally move the helper function into the effect.
‫And so this is also great demonstration
‫that we should in fact have one effect
‫for each side effect that we want to have.
‫Or in other words, this effect here should
‫only be responsible for setting the duration,
‫not for setting the duration and playing a sound.
‫So instead we just create one effect
‫that is responsible for playing the sound.
‫And we do that whenever the duration changes.
‫So here we actually like voluntarily declared
‫this duration variable in the dependency array,
‫even though we are not using it anywhere here.
‫So this is simply to tell the effect that we wanted
‫to run whenever the duration changes.
‫And now here we are then missing this reactive value again.
‫So let's place that here.
‫And with this, everything should be well.
‫So let's just reload this and now it works here,
‫it works here.
‫So both the sound and the functionality.
‫And when I click here, it will not reset anything.
‫So it's gonna work just as expected.
‫And also just like before
‫when I now click here, the sound will play.
‫And so the reason for that is this allowSound variable
‫right here in the dependency array.
‫So causing this play sound function to play,
‫which even makes sense in this situation.
‫So when we turn it off, we hear no sound.
‫And then just as an indication that it worked,
‫we immediately get that sound feedback.
‫Nice, so this was quite a journey where we explored
‫a little bit deeper how these dependency array works.
‫And how these different hooks interact with one another.
‫So that thought process that I showed you
‫I think is pretty important.
‫And so I hope that you liked this lecture.
‫So this deep dive into useEffect
‫and into all the techniques
‫that we can use together with it.