Goodbye, useEffect - David Kho…
Highlights
- all right all right hello everyone hello react Brussels it’s been many years since I’ve been in Belgium so I’m so glad to be back here again this is basically going to be a crash course where we are going to learn the right way to use effect and saying goodbye to all of the other use effects that we really don’t need in our application so buckle up we are we are in for a ride hopefully you will learn a lot of things today but first of all I’m extremely happy to be here who’s happy
to be here at reacts Brussels yeah all right who’s uh who’s a little sad that you know it’s it’s ending so soon I mean we we had we had a lot of amazing talks like some of my favorite talks today uh how many of you feel like this have you seen this smiley before this is the frustrated react developer Smiley so yeah so of course
take care now I I learned hooks I um I I was actually fortunate enough to get a preview of hooks when they first came out and they all looked really interesting except use effect I’m like all right that’s gonna be an interesting one and then uh you know people started saying okay use the fact I have an effect this is where it goes but then the problems kept creeping up and I’m sure in your code bases if you’re using react uh you know you might have some
really nasty use effects in there but if you’re struggling with use effects don’t worry even senior react developers struggle with it if anyone tells you otherwise they’re not making you know good enough react applications because you do need use effects in your application and you might have this big nasty dependency array and if statements it’s all very typical it’s just a really awkward hook all right so uh typically this is what our you know use effects looks like we have a
use effect that does something we have a cleanup dependencies all is fine you know it might have worked before but then guess what react 18 came out and it rendered this again so it ran the effects twice on Mount in straight mode how many of you have actually ran into that or is that just a me problem okay a bunch of you so uh use the fact if I were to summarize this talking just one slide it’s not for all effects in fact I would
say it’s even confusingly named it shouldn’t be used effect it should be used synchronized but we’re going to be talking about that in a minute so what was life before like before use effects well we had component did Mount component did update and component will unmount and these were all convenient places to put your effects especially the effects that were long lived inside of your class-based react components and so when we moved to hooks thankfully uh
we we need to figure out okay I have these please these effects in my life cycle hooks so where do they go now well we put all of our componented mounts effects inside of this one with an empty dependency array we put the ones where it happened on component did update in a non-empty dependency arrayed use effects and then this awkward looking uh component will unmount it goes in use effects with this return function and this just looks really really awkward so
I want to say first and foremost that use effect is not a life cycle hook and while you could use it that way and it is expected to run at the exact same time as you mount your component unmounts and change it’s not the way that you should be thinking about things uh Danny abramov even said that the mental model of use effect is synchronization not life cycle and so we’re going to be talking about why exactly that is all right so uh you know we have our use
effects we have the effect in there we’re doing something and the dependency array it’s uh you know this is when that effect is going to be executed now react is supposed to be this declarative framework but honestly this might feel like okay we’re doing our effects in a declarative way but in reality there is a ton of indirection over here so take the imperative approach first like when something happens like an event or you know something else a button is pushed a
form is submitted execute this effect you might be looking at this and saying okay that’s the imperative approach the declarative approach with use effect looks more like this when something happens and uh you know it causes the state to change then depending on which parts of that state change which is the dependency array this effect should be executed see how it’s more declarative right but only if some condition is true inside of my use effects also reacts May
execute it again for some future reason but only in strict mode which you shouldn’t disable for some future reason so I mean honestly whatever your opinion is on imperative versus declarative I prefer the imperative approach and you could express it in this imperative approach in a declarative way we’ll be talking about that later too but some of you might be thinking you know what I didn’t really have a problem with use effects like I just do something I return a cleanup and I put
things in my dependency array everything is fine but the more you add features and and changes to your application your use effects start to look more like this where we have a bigger dependency array we have multiple use effects we forget the cleanup and we have this nasty conditional in here and we’re doing things depending on what’s inside there so we’re trying to control the fire hose of changes happening so that our effects
happens at exactly the right time and I’ve seen this code all over the place I’ve searched Source graph for examples and there’s just plenty of examples this is a particularly nasty one and so it really uh it really showed me that dependencies are really the wrong mental model for effects we want effects to execute when things happen not exactly when things change so let’s get back to the original issue react 18 running effects twice on mounts in strict mode
how do we fix this in first of all why does this happen so react is actually doing this on purpose behind the scenes it’s not a bug or anything it’s mounting the components and then it’s doing a simulated unmount of that component which is calling the cleanup of the effect and immediately afterwards it’s remounting uh the effect so um you get your double execution of the effects and so uh you know when I first ran into this I was like this is a bad
hook it’s use defect you know it feels like a major major foot gun but honestly this was reacts way at least react to 18’s way of telling you hey you’re using the use effect hook wrong so what is use effects for it’s for synchronization and so there’s a difference between fire and forget effects and synchronizing something in your component with some outside source so uh take this example we’re
synchronizing with some external API some story API so that uh whenever the item changes we’re we’re getting this item data and we return an uh an unsubscribe function and this is going to change whenever our item changes because we need to unsubscribe to the old item and re-subscribe to the new item now doing something like this means because you’re just keeping track of some external thing we could unsubscribe and resubscribe multiple times it
doesn’t matter it’s like watching TV if you put on the news you could turn the TV on and off you could change channels you could go back to the previous channel that news channel is still going to be the same so that’s sort of the mental model that you should be thinking of with use effects um the react documentation distinguishes between effects and event handlers so uh when react is talking about effects with the capital E they’re talking about
long-lived effects so these subscriptions that I’m talking about when uh we’re talking about fire and forget effects uh reacts in the docs mentions that as event handlers so here’s the difference a fire and forget effect you don’t care what the results of this could be a console log an analytics call maybe you’re sending some data asynchronously but you’re not awaiting a response a synchronized effect is when you’re actually communicating with an external system so
this effect could actually be long-lived and so t