We've now seen some really weird behavior in this very small example.
So let's not take a look at a quick diagram to understand exactly what is going on inside of here.
So quick diagram.
Here we go.
This is a diagram of what's going on inside that code pen example.
During the very first time that the app component is rendered to the screen so the very first time it
gets rendered we're calling counter or we're setting up a counter piece of states in initializing it
to zero.
We then call that use effect function.
Inside there we set up these set interval call and it has a direct reference to that counter variable
like so.
So we can kind of imagine that inside of sound set interval.
The counter references that counter variable that currently has a value of zero.
Right.
Simple enough.
So what really goes on during any time we press the increment or decrement button.
Well as usual because we're pressing increment or decrement right there we call set counter which remember
is going to rerun our component automatically during that re render.
We are not going to run the use effect function because we put in that argument of an empty array as
the second argument so we can kind of imagine that we then get that second render so going to duplicate
that box moved over here.
Call it second time render during that second render the value of counter might go up to is 1 or negative
1 depending on what button gets pressed.
So the value of counter definitely is now different.
However during the second render we do not rerun the use effect function a second time that doesn't
run instead because we put in that empty array use effect does not get invoked.
Now why is that relevant.
Well they say the set interval that we set up during the first time render is still running in the background
and the core issue here is that that set interval function still has a reference to that old version
of the counter variable.
There's nothing inside of here that somehow tells that set interval hey the value of counter changed.
Instead we are working with a completely new variable called counter the first time render has one version
of the counter variable.
So that is like one variable sitting in memory and our set interval is referencing that variable in
memory.
The second time we run our component a completely new counter variable is created in memory.
And this has a completely different value than the original account or variable that was created over
here.
So set interval still has a reference to the old value of counter.
And like I said there's nothing to somehow tell it to stop looking at that old value and start looking
at the new value instead.
We don't have any reasonable way of telling the set interval to say hey make sure you go and use this
new variable in memory as opposed to the old one so that's essentially what's going on every single
time we update our component or render it at all.
There's nothing to go on or no mechanism to somehow reach in to set interval and tell it to use the
new value of counter forever it's going to be referencing that original value.
So how can we fix this.
Well one way we could fix it back over encode ban would be to remove that empty array right there.
So if we removed that empty array it means that we are now going to call that inner function.
So that one right there every single time we re render our component.
So if I remove that empty Ray and then click on increment will now see a new interval console I'd write
your new console log for that value of counter.
You'll notice that we're still getting some values of zero console logged out as well.
That's because remember now every single time that we re render app we're setting up a new interval.
So we're going to always be seeing a console log of every different version of counter that we ever
encountered.
So if I now click on increment a couple of times we're essentially setting up a bunch of different intervals
each of which have a reference to a different value of counter.
So now inside my console I see everything from zero all the way to nine being console logged one by
one.
So this is essentially the same issue that's going on inside of our project right now.
But understanding exactly what's going on is just all a bit more complicated because we are working
with a lot more data than inside of this very simple example so let's now take this knowledge and apply
it to our application and understand why our use effect call is not quite working out as expected so
back inside my code.
Ed I want to remind you of two things very quickly.
First off inside a track create screen right here.
We put together this callback function that we pass in to use location inside of that callback function.
We have a reference to this variable of state DOT recording.
So just keep that in mind for a second then inside of use location.
So here's the hook we received that callback inside of use effect.
We call start watching that runs our start watching function right here and inside of start watching.
We have a reference to that same callback function that we just passed in.
So what those two things in mind.
Let's not take a look at a diagram and understand exactly what's going wrong inside of use location.
All right.
So we've got a similar diagram here but give me just a little bit more complicated so inside of track
create screen.
I want you to imagine what occurs during the very first render of our application the very first render
we're going to have a default value of recording set to false because remember by default our recording
values false which means we are not recording a track at that point in time inside of track rate screen
we assemble that callback function inside that callback function.
We have a direct reference to that recording variable.
So that's inside of a track create screen right there.
State DOT recording a direct reference to that variable so we can imagine that that green box right
there is referring to that copy of the recording variable.
Now I know that technically we're referring to state DOT recording but the idea is the same.
Essentially we've got some a variable in memory and its current value is false.
We then take that callback and pass it into the use location hook.
So during the first call of use location we run that use effect hook.
Right.
That's use effect right down here inside of U.S. fact we call start watching.
So we call start watching so then start watching calls or runs excuse me and instead of start watching
once we go through all that permission stuff.
And once we start watching the user's location we then eventually run our callback function.
So that orange callback box right there that's essentially that callback function right there.
So we are running that callback function and inside that callback function we have a direct reference
to that recording value variable in its current value is false so same thing that we are going through
inside of code pen right now.
So now we want you to think about what happens whenever we press that start recording button on our
track create screen or inside the track form whenever we click start recording right there what goes
on.
Well we essentially are going to re render our track create screen a second time.
So going to duplicate that box over here so we're going to get I've kind of already made that diagram
we delete this one right here.
There we go that's better.
So we are going to run track rate screen a second time at this point.
Recording is now going to be equal to true.
We then recreate our callback function.
So the callback function does successfully get recreated.
Right.
So we are creating a second version of it back inside of track create screen right here we create that
function a second time.
And now that function does have the correct reference to the recording variable it now says OK recording
is 100 percent set to true.
However what happens inside of use location so we can imagine that during that second re render we call
use location a second time.
Now here's the issue.
The second time use effect does not get invoked again.
We don't call it a second time.
The only time that we ever call U.S. fact again back over here inside of your location is when the value
of should track changes when a user taps on that state DOT or that start recording button we change
the recording variable not should track or anything like that.
So the second time that we run use location this function right here doesn't run.
It doesn't get invoked because that does not run.
That means that start watching doesn't get ran.
So start watching doesn't get ran and nothing inside of here.
Nothing inside of you.
Use location somehow reaches back over to this previous version of everything we executed and tells
that old version of start watching to start using the new callback that was passed in.
So it's the very same scenario that we are in inside of code Penn.
I know it's kind of different because I had said previously hey this like we're referencing this old
value of recording or stuff like that.
We essentially still are.
I know the callback is getting a reference to the latest version that we're creating over here.
The issue this time around is that we don't ever get a reference to that callback into art start watching
function.
So the copy of Start watching that is currently running the copy of that watch location async that we're
running still has a reference to the old callback and the old callback still thinks that recording is
equal to False so why is that relevant.
Well remember that recording variable controls whether or not we are passing in back inside of art location
context here's add location right here.
That recording variable gets passed into add location and it is solely that recording variable that
controls whether or not we add in this most recent location to our array of locations.
So inside of your recording is always going to be equal to False no matter what even if inside of our
state object we somehow update the value of recording whenever we call add location recording will always
be false which means we're never going to dispatch that action and we can very easily test this out
inside of here right after dispatch we can put in a console log of recording like so if I now go back
over and hit start recording we're definitely calling at location right now.
Without a doubt because remember ad location is in charge of updating that little circle.
So because that circle is moving we know that ad location is being invoked.
So if we go back over to our terminal we're going to see that we get a bunch of false statements right
here.
So false means state DOT recording is set to false.
So it's hundred percent false that means we're never going to dispatch that action to add our location
to the array of locations and therefore our array of locations always has a length of zero as a little
bit more debugging that you might want to try out here just to look kind of like verify what's going
on.
We could also go back over the track create screen inside of track rate screen right above where we
call use location we can put in a console log of state DOT recording and write about before that value
I'll put in something that says like outside.
So this is the value of state DOT recording outside our callback and output as similar council log and
say inside.
So take a look at this now we've got state DOT recording and state DOT recording.
Let's now save this and see what happens it's all save it go back over and check create hit start recording
go back over my terminal and take a look at that we've now got an inside of false and an outside of
true so outside that callback recording is set to true inside of it it's set to false and like we just
discussed that's a hundred percent because our start watching function is still calling the original
callback that we put together and passed down into use location during the first render a second render
occurred and we've got a new callback being assembled and we're passing that callback into use location
but it just never gets used.
So start watching is always calling that first version of our callback which always has a recording
flag a false.
So that's what's going on here.
And as you can imagine this is a super nasty bug.
This is like the worst thing you can possibly encounter.
So this is without a doubt in remove those council logs by the way without a doubt this is like one
the worse things around making use of hooks.
It is incredibly easy to fall into traps like this specifically around use effect.
And it's really hard to debug and figure out what's going on.
So clearly we would love to have some kind of strategy to mitigate this and try to figure out some way
to not run into issues like this in the future.
So let's take a pause right here when we come back the next video we're going to figure out how we can
solve the issue that we're currently running into.
And we're also going to discuss a couple of ways that we can kind of avoid running into issues like
this at some point in the future as well so quick pause I'll see you in just a minute.