Be Cautious of React.useEffect Race Condition Bugs | JavaScript

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello friends today i'll be covering race conditions and react.use effect and some of the bugs you may experience because of it so what is a race condition a race condition can happen when you have two asynchronous processes that'll both be updating the same value and in this scenario it's the last process to complete that ends up updating the value and this may not be what we want we might want the last process to be started to update the value an example of this is if your component fetches data and then re-renders and fetches a new set of data you would want the new set of data to update the value but first i'd like to thank some of the new subscribers to the channel so thank you tirapot spe grope luciano brian tanjeet mba x 333 pavel joel james sarge john dimitar shin lorenzo vince sebastian sajeed farooq vettel karen dijaro nw famir shimo ignacio and ahmed it's your support that keeps a small channel like this going and i really do appreciate each and every one of you so thanks a lot so let's see what that might actually look like here i have a react component with two buttons each of these buttons perform an api call one fetches the data for luke skywalker and two fetches the data for c3po and to simulate the worst case scenario i've added an artificial delay of one second to c3po so every time it fetches the data it's going to lag by one second and so here i'll click luke skywalker you can see that it returns the result and i'll click c3po and it returns the result after one second and to initiate the race condition what i have to do is fire off the slow process the c-3po and then fire off the fast process immediately afterwards so i'll go ahead and click the loop skywalker button just to reset it and what i'm going to do again is click two and then click one real fast so i'm gonna click two and then click one and here's the bug we're looking at right now you can see one equals c3po so one should be luke skywalker and two should be three cps so one equals three cpo is definitely a bug in my application and let's jump into the code to see what's wrong here so when we're looking at this use effect you can see it looks pretty standard uh first it sets the person to null when it enters it then performs a call to get person from my api it passes in the id then when that returns all it does is it calls set person it's difficult to tell just by looking at use effect what the problem is but anytime you have an asynchronous call inside of use effect you can have a race condition bug so what's happening here is get person starts running the components re-rendered and then a second get person call is running now we have two calls to get person running simultaneously this is where the race condition bug comes in because we actually don't know which race is going to complete last because that's going to be the one to actually win the update and set the person there's a couple of different ways to fix this the first way is to abort the call and if you're using something like fetch it has an abort controller and it will let you abort the initial request but for this example let's just pretend our request is unabortable what i can do is put in a value here just called cancelled and i'm going to set that to false and what i'm going to do inside of get person is i'm going to say if this event has been canceled then i'm going to exit so i'm not going to call set person if the event is canceled now when the component unmounts and this is the syntax here for the unmount event all i have to do is set cancel to true the trick on why this works is due to closures so every call to use effect is going to create its own closure and they're each going to have their own canceled value inside so when i call this with id1 and id2 they will each have their own closures with their own cancelled inside so the second time the component renders it's actually going to call the unmount here of the first call which will then set the first calls canceled to true and that way if get person completes out of order we'll always have this line here that is going to check to see if it's cancelled and then just ignore the updates and now that you know how to do it manually let's do it the easy way so i'd recommend using a library for this uh the current one that i'd recommend is called react query not only does it solve the race condition bugs but it also comes with a very powerful tool set and let's see what this will look like with the use query library so i'm just going to type in here is loading there is an error object but just for the brevity of this video i'm going to ignore that and just use the data but you should definitely use the error so i'm going to import use query and i'm going to add the cache key in here which i'm going to call person and id and that's going to uniquely cache the results of this query into its own internal cache that'll just make things load a lot faster so if i have to refetch this data it actually won't make another network call it'll just pull it straight from the cache now use query takes a second parameter which is a callback function and that takes the key as well as the ids you're being passed in so these these two items here will be passed into here and what's going to be called here is just get person with the id so i'm just going to comment out the use effect code because we're not going to be using any of that and all i have to do is say const person equals and i'm just going to see if it is loading if it's loading i'm just going to return null for now and if it isn't loading that means i have access to the data so i'm just going ahead and set the person to data and that's because down here i'm checking to see if it's a person and i'm going to format it like this otherwise it just returns null and if i open up my browser again i'm just going to check to see if it's working so if i click one luke skywalker comes and 3cpo is also working and as an added bonus you can see if i click back and forth here these values are loading instantaneously so the delay in c3po isn't even triggering anymore because it's actually pulling these values from cache so not to simulate our race condition i'm going to have to reload the application which is going to clear the cache and then i'll just click two and one really quick and you can see that over here it actually did make both of the calls and here we're looking at the correct value whereas before it was saying 1 equals c3po and now it's saying 1 equals luke skywalker and react query has completely eliminated our race condition as well as added caching into the application so i'm going to go into the code again and then just delete all of this unnecessary code and you can see how simple our application has become it's actually a lot less code than before by just using the use query so just to recap a race condition bug can occur when two asynchronous processes are started and they complete out of order and we can solve this by either aborting the first request keeping an is canceled flag or by using a library like react query and thank you for making it to the end of the video i really do appreciate you spending your time with me and like always i'll see the next video you
Info
Channel: Joel Codes
Views: 4,934
Rating: undefined out of 5
Keywords:
Id: SYs5E4yrtpY
Channel Id: undefined
Length: 7min 46sec (466 seconds)
Published: Tue Sep 22 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.