Adiós, useEffect: Managing Effects More Effectively
Watch on YouTube (React Alicante)
What is this talk about?
“If we add some things to the dependency array, and so whenever those things change, then our effects that we use to putting a component did update, go inside useEffects and then our component will unmount.”
“Beta docs explain how, you know, effects are going to run on every render.”
From the opening of the talk.
Key takeaways
- If we add some things to the dependency array, and so whenever those things change, then our effects that we use to putting a component did update, go inside useEffects and then our component will unmount. 4:00
- Instead of thinking that the next state comes from the current state and the event that happens, we can say that the effects come from the current state. 16:00
- Just because we think that useEffect is the right place to calculate derived data instead, honestly, just do it right in the components, you don't need useEffect. 21:00
- You notice that every arrow that's coming from this full video state is going to execute the pause video effects. 29:00
- The React beta docs have a section on what you should do instead of just fetching data inside of your useEffect. 40:00
Quoted from the transcript.
Full transcript
From YouTube auto-captions. Punctuation and capitals were restored automatically. Technical terms were normalized; some errors remain. 7,026 words.
0:00 Introduction
My name is David Khourshid, and, my talk was originally titled goodbye. useEffect, but we're in Spain, so I ran it through Google translate and I got this translation. We're gonna be talking about managing effects more effectively in React. But first, a little bit about me. I traveled a long way to get here to give you an idea. Right now we're here. And I came from over here, right by that hurricane, and, you know, that's why, thankfully, I'm really happy to be here. I'm from Orlando Florida, and I, I was actually really happy to escape that hurricane and come over here. So we're all, you know, myself included, probably feeling a lot of emotions, you know, happy, you know. I'm a little bit worried because I lost power and stuff back home, so we'll see what happens. There was also flooding. You know, some of you are sad because you want coffee, I want coffee too. And some of you are feeling like this.
Do you know what this emotion is? This is the emotion of a frustrated React developer working with useEffects. And so that's what we're going to be talking about today. [Applause] all right. So first of all, we're talking about our favorite hook today. Of course, useEffects, and, for some of you, you know you, you might have been like, Okay, useEffect was fine. I didn't really have any problems with it. And some of you are, like me, where you're like, just at this, you know? Um? But honestly, if you're struggling with use bet, don't worry, because even senior React developers struggle with it. Okay, the you might have a large dependency array, you might have a lot of IF statements inside, and that's typical. Okay, it's just a really, really awkward hook. And so, you know, when you first started learning useEffect, you might have stumbled a little bit, and then, you know, after a while, you might have gotten used to it.
2:00 We had components, did mounts right where you could run some…
You said, Okay, I understand useEffect enough. I know that we could do something and useEffect, and then we could return a function that cleans up that useEffect. And we could also put some dependencies in the dependency array, and whenever those change, the effects will run and. So now we could predict exactly when our effects are going to run, but guess what? In React 18, that changes because React 18 runs effects twice. When you mount on strict mode, which you should be in, because if you're not in strict mode, the React core team will yell at you. So stains trick mode, all right. So useEffects, if I were to summarize, this entire talk is not for all effects. In fact, you could say it's probably confusingly named, and so if you take anything from this talk, this is the main point. And so we're going to learn how to best use useEffect. And what are some other patterns and hooks that you could use for things that you might have typically used the useEffect?
Hooked for? I'm using the word use a lot, it's really confusing, all right. So what was time like before? useEffect? Well, we have three main things. We had components, did mounts right where you could run some effects in there, you also had components, did updates where whenever, whenever things changed. You could run an effect, and also you had components will unmount. Where you could do probably some cleanup. If you wanted to run some extra effects in there, then you could do it, and so if you wanted to run an effect. That lasted for the lifetime. Of the components, you would start in component to mount, and then you would clean that up in components will unmount. So what do we have now? You know? Now that we've gotten rid of class components, we're not using them anymore, hopefully we're all using hooks. Well, now we have components and mounts in use. Effects, sort of, I mean, remember, it's rendering twice, so that sort of idea goes away.
We have component didn't update. If we add some things to the dependency array, and so whenever those things change, then our effects that we use to putting a component did update, go inside useEffects and then our component will unmount. Is sort of in this awkward, you know, double function type of thing, where we're returning the disposal function and we have an anti-dependency array. And that's when our cleanup effects are going to happen. But this is actually sort of the wrong way of thinking, because use. Effect is not really a life cycle hook, and it's it's not that you can't use the exact same way as you use components, it mounts, component will, amounts, and all of that. It's that's not exactly the mental model that you should be thinking of when using useEffects. So, Danny Vermov, the supposed creator of React, just kidding, he's just creator of Redux, uh.
5:00 You put in effect and useEffect…
He says that the mental model is synchronization, not life cycle. So that's the key word that I want you to keep in mind. When talking about use, the fact is that we're synchronizing, we're not actually using it for those fire and forget effects. So when I was starting off with useEffects, I ran into some problems. And so some of these problems are in the form of infinite loops. And, thankfully or not, thankfully, uh. This was actually, caused when I was trying to fetch some data, which caused lots of API calls to be made. And if that happens in production, that could be really, really, really bad. And so that's why it's odd that when you're first starting to learn useEffect, it seems like the default behavior, if you're not using it correctly, is to cause an infinite loop. And so, just to show you an example, let's say that we're setting counts inside this useEffects. You might say, Okay, yeah, it's going to increment it by one, but then you actually run this in your app and what happens?
You get this? So, this seems odd. You're like, Okay, I was just trying to run a useEffect. Why is it infinitely incrementing my counter? Well, useEffect is not a state Setter. And we're going to talk about that a little bit later. But, yeah, you might look at this and say, hey, I know enough React that you should have used a dependency array, at the very least. And also the, the new reacts. Beta docs explain how, you know, effects are going to run on every render. So when you set count, it's going to cause a re-render, and then it's going to cause that effect to run again. And then you get that infinite loop, uh. But it's really easy to run into this problem when you're first learning use. Effects because this is from the official documentation, there is no dependency array. It just shows document.title and then you set the document title.
Thankfully, we're not setting state in here, but it's very easy to see that we could replace, mutating document.title with settings state somewhere else. It just becomes a, you know, just a easy comparison to make. So the problem is that in the currents, reacts docs, this idea of a dependency array does not actually appear in the documentation until the very end. And it's as a tip, it's a tip for optimizing performance by skipping effects instead of being one of the main concepts of effects. All right, so what's the standard way to useEffects? Well, you put in effect and useEffect, and then you have a dependency array. And so the mental model again is synchronization. So whenever the things in the dependency array change, then these this effect is going to run again. You might think, okay, simple, this is a very simple way of, you know, just declaring an effect inside your components. So, in my view, this is actually sort of an imperative.
Or, sorry, it's sort of, I. I guess we would say, oh. This is a declarative way of representing effects, because the imperative way is saying, when something happens, execute this effect. And so, you know, a lot of you might be thinking, declarative is better than imperative, but what is the so-called declarative model that useEffects sets? Well, it says when something happens, it will cause the state to change, and depending on which parts of that state change. Which is the dependency array, this effect should be executed, which is more declarative than execute this effect. But also, this should only happen if some condition inside of our useEffect is true and reacts by the way. May decide to execute it again for some future reason, but only in strict mode, which you should not disable for some future reason. I'm actually, you know, I heard the explanation a dozen times, why? You shouldn't disable strict mode for this?
And Y reacts, executes it twice, and I, I still forget. So, ideally, our code looks like this, you know, we have a useEffect, we have an effect in there, we have a cleanup function. But in reality, it looks more like this. Where we add more and more to our effects just to get it synchronized just right so that our effects runs exactly when we need it to. And, you know, sometimes we forget the cleanup, in fact, a lot of times we forget the cleanup function, and we also have a big, nasty dependency array at the very end. And don't take my word for it, just look at code online, look at your own code basis. This kind of pattern is everywhere. This is just some example code I found. Here is one with many, many, is variables, and it's just a very, very confusing mess. So, in my view, dependencies are the wrong mental model for effects. All right, so let's go back to the original problem, React 18 running effects twice whenever we Mount.
10:00 Action effects actually should happen outside of the rendering cycle…
So how exactly do we fix this? Well, first, let's explain what is happening inside of React. We're mounting in effects, and then React is going to do something really quickly, it's going to unmount that component. And so that's going to cause, called the cleanup function, and then it's going to remount it again. And, I think the reacting said that this happens when you need you have some sort of off-screen API where things can close and open really quickly. Your effects should be resilient enough to having that component be quickly unmounted and remounted. But this is what's happening behind this, behind the scenes, and there's no really clean way to catch it. And you shouldn't be doing it either. And so we'll talk about that in a minute. So if you've run into this problem, which I have, especially those of you who have been, who have been very cautious about performance and memoization.
And thinking like, let's keep our re-renders to a minimum. And then you install React 18, and then you realize, why do I have twice as many re-renders? Now? I must be doing something wrong. No, it's actually now the default behavior of useEffects, which might feel like use defects or like a foot gun. And really, it is, and that's because I feel it's improperly named. It should really be used synchronization, and that's because the main use case of you useEffect is actually synchronization, it's. Not really for executing effects. So an example of something, synchronizing would be us subscribing to something, and so getting state from something, doing something with that value and so on. We unsubscribe when the input in our dependency array changes, or when the component is unmounted, so synchronization is the key word for useEffects. And so here's an example. Let's see that we have a store API and we're subscribing to some item, like, let's say that, you know, this item can change.
Or we're keeping track of the, the stock quantity or something. We could subscribe to that in the useEffects, and then we could unsubscribe when we're no longer needing to listen for that subscription data. And so, you know, we subscribe to it. We synchronize with an external system and then we dispose, and our dependency array allows us to re-subscribe whenever, the dependencies inside our effects change. And so, in the beta React docs. They talk about two different types of effects, which, you know, they have with the capital E, just to distinguish from other effects or side effects. And it's that we have effects which are sort of long running and they're more of the synchronization subscription type of thing. And then we have effects which are more fire and forgets, or event effects. Like they're called in React. So here's a visual of the difference. A fire and forget effect is something that just happens once and you don't care about the results, so again, this is like a fire and forget.
Like you're making a log, or it's an elementary call, or you're sending some data to an AP API, and you don't care whether that response succeeds or fails. A synchronized effect is an effect where you're actually communicating with an external system. And so you might need to send messages to that system, and you might need to receive messages from that system. So a patch request is a, you know, it's actually a really good example of this. Because we are waiting for a message from an external system and so we're trying to synchronize with that, you know, third-party API and also synchronized effects can be resilient to being unmounted and remounted because that system, that external system, doesn't really go away. We're just. Deciding that we're going to either change the subscription or we're going to stop, synchronizing with it, and then start synchronizing with it again. Uh. When, for example, our component comes back into view, okay, so that's synchronizing effects, so where do action effects go then?
Well, first of all, we know that we can't do any side effects in render. And of course, putting things in useEffect is awkward, like we talked about. So do they go outside the component, like, where is left for these effects that we want to execute to go? Well? Let's talk about, you know, event handlers when we, uh. We know that when we're putting in effect inside the components, like we've seen before, React is going to double mounts that component. And you could imagine this being, you know, double mounted, triple mounted, whatever. But that effect is going to run multiple times instead, if we put the effect in the event handler, then we know it's only going to happen once. And so it doesn't matter how many times a component re-renders. So action effects actually should happen outside of the rendering cycle, so these action effects go inside of the vent handlers. Actually, sort of, you know, we're going to talk about some pros and cons of this approach.
And so one classic example is submitting form data, where, yeah, so when you're submitting form data. Instead of having some sort of, useEffect for that, you could just put it right inside of on submits. So, right now, when we're using useEffect for these effects, we sort of have a convoluted way of thinking about when that effect is actually going to execute. If we put it inside of the event handler, then we know that when some event happens, that effect is going to immediately happen. When you're using useEffects, then when an event happens, you might cause a state to change, which will then cause that effect to run, because, remember, that state is in the dependency array. And sometimes it's sort of like dominoes, where one state change might cause another state change and another one. And then some effects will run based on some, you know, some transient states change, so this becomes really confusing to think about when effects.
Are actually happening, and so I think part of the problem is how, React, sort of approaches, how, you know. UI is a function of states, and Redox also popularized the fact that the next state is derived from the current state in the event. But both of these, relations seem to miss the whole effects parts, like, where do effects fit in to all of this? Well? Instead of thinking that the next state comes from the current state and the event that happens, we can say that the effects come from the current state. And the event that happens, as well as the next states. So if you think about the relation this way, it sort of feels like the Elm architecture, and, it's. It's actually a really great way of thinking of effects, where when an event happens, you're going to think of, okay. This is what the new state of this is going to be. And this is what effects are going to be rendered or executed, so when do effects happen?
You know, you might think, okay, if I'm using some library like Redux, it might happen in middleware or callbacks or Sagas. Reactions. Monads. I don't know. So they could happen in many different places, but really, they happen in these state transitions, which are caused by these events being, you know, being sent. And so that's why moving effects closer to event handlers actually makes your effects, you know, make more sense. So where do these action events effects go in these state transitions, which happen to be executed at the same time as event handlers?
18:00 Instead, have this as a side effect inside of the on…
So in the you know, in the beta Reacts documentation, they even have an entire section called you might not need an Effect. And so I included this because I want to show people that it's not just me. Talking crap about useEffects. The React documentation actually says there's many use cases where you might not actually need an effect. And by the way, they just released a little Banner. So when you go to the main Reacts page at React to Js..org, now you see this link to beta..React..js..org. And I really encourage you if you're learning Reactor, you want to reference its API, even if you know React, go to the beta sites, read the documentation. It's. Really, really good, and a lot more up to date than the current documentation. Okay, so, first of all, you don't need useEffects for handling user events, so, like we said, instead of using useEffect, we could use an event handler. So let's take this example, this is an example again for submitting form data, where we have a big useEffect over here. And, you know, we're doing a bunch of things, we're keeping track.
If the form is canceled, this is being triggered. If we set is loading to true. So again, it's like that domino effect that when we set data now, we're going to trigger an effects to happen. So, in on submit, we're just setting is loading to true and we're setting the form data to the event. And so that's going to trigger, that's which is going to trigger all of this. And then we have to keep track of cancellation and errors and stuff this gets really ugly and hard to track. So instead, have this as a side effect inside of the on submit event handler. You might also like, run into some problems with this approach, too. Where you do still have to keep track of his loading, which might be some state in your components. And then you execute the side effects. So you have to set the IS loading flag to false and then you also have to keep track of errors. So, you know, that's, you know, kept track of in here.
And then you also have to keep track of cancellation, which I didn't even put inside of here. Which is why when you trigger an effect, it's best done in an event handler. But that doesn't mean that you have to shove all of your logic inside the event handler. Instead. You could just, you know, send an event somewhere, and so that's going to immediately do all the logic that you have. So in this case, I moved all of my logic to the use checkout form. And, you know, then all I have to do when I call on submit is send that event. And that, you know, that effect will be executed inside of my hook instead of inside my components. Okay, so, second thing, you don't need useEffect for transforming data, so, instead. Of useEffects, we could just do it right in the components, like you'll see here. So, in this case, again, we're doing a shopping cart example.
I'm keeping track of the total amounts of items in my carts. And so or sorry. The total price of all the items. And so whenever the items change, I'm going to calculate the total price by using this items.reduce. Here's the problem with this. This is actually going to cause two renders, so one render is going to happen when the items change. And then we're going to call this useEffect, change the total, and that's going to cause another render. So we're doing an unnecessary number of renders. Just because we think that useEffect is the right place to calculate derived data instead, honestly, just do it right in the components, you don't need useEffect. And in fact, if you really want to useMemo, you can. But it's really most of the time an unnecessary performance optimization. And sometimes, if you have enough of those, that could actually make your app slower, so just do it inside of the components.
Okay, so, third thing, you don't need useEffect for communicating with parents components. Instead, you could actually do this right in the event handler, like we talked about. So, one classic case is you might have an on open and on closed prop where your parents can actually put some event handling logic in there. For, you know, let's say you close a product and you wanted to, to do something when it closes, or when it opens, you want to do something else. So we might have this is open said. This opens dates inside of our components. And whenever that state changes again domino effect, we're going to cause that state to change, which is going to cause this effect to be executed. And again, it's going to probably cause another render because you're doing it at a different time than when the events actually happened. So instead, let's try this move this to an event handler, which is just a function inside of our component opponents.
This toggle view function and you're going to calculate the next state, which is it's not open, or it is open if it wasn't open. So you're basically toggling, between the views. And you're going to do two things if you really need that statement, you could set is open, and set that state over there, and then directly inside this event handler, you could call on open or on close. And so, you could even move this out into a hook and moving your event handling, or, sorry, your effects logic into an event handler actually makes it really easy to abstract into a custom hook. You know, just going back to that first talk, separation and concerns and all that, it becomes a lot easier to separate that business logic to a, a more specific hook. Like, use toggle, and then you could use it directly inside of your components. Everything is a lot cleaner that way. There's no useEffect Insight here, it's a beautiful site, all right.
24:00 I, I maintain XState at Stately..ai, we're a sponsorber right there…
So next thing, you actually don't need useEffect for subscribing to external stores. And I know you might be thinking, wait a minute, didn't you just say that we would use useEffects for synchronization and subscriptions? Well, yes, and no. So, for some things, like when you're listening for data coming in from an external store. There's this really, really useful hook that I wish that we used a lot more, which is useSyncExternalStore, so I really encourage you to look it up. It sounds complicated, it's really actually a lot simpler than useEffects, so take this example. Let's say that we're listening for, when we're connected or disconnected, like sort of an online offline connection thing. We're doing a bunch of things. We're keeping track of the states, we're managing a subscription inside, and we're setting the, you know, whether it's connected based on the status of that. And we're also, you know, making sure to clean up our subscription when we unmount our component.
Because we don't want to keep listening unnecessarily. This looks a little bit messy, but this is, to be fair, a valid use case of useEffect. If you don't want to use, useSyncExternalStore, so check this out. Instead of this, you could just useSyncExternalStore. Where you give it three arguments first the subscription part, then the then you're going to give it what the current state is. And this is called the get snapshot function. And then you, just pass in a variable for, for renderings, or for just telling the server side like, what the default state is. And so this makes it really, really easy to work with external stores because you don't have to go through all of that. Juggling. With you state and useEffect and the dependency array and the cleanup because you sync, external store is going to manage that all for you. So, again, this is really, really useful.
I, I maintain XState at Stately..ai, we're a sponsorber right there, and, in XState, our useMachine hook actually does use the useSyncExternalStore hook inside of it to help manage. States and exit has actually a pretty interesting approach to using effects, and it's to make it as declarative as possible. With X8, which is the library for creating state machines and statecharts, and JavaScript, you have three, you. You have a couple of different types of effects, you have actions, transition actions, and also you have invocations, and so these actions and invocations, they represent effects that happen during state transitions. And it actually makes it really easy to really predict when effects are going to happen. And so I'm going to show you a quick demo of that over here.
27:00 The video has ended, then the video is going to both…
We're going to do not too much coding, just a little a bit of diagramming. So, for example, this is a cool video. It doesn't really work right now, but here's how I want it to work. When you click the video, I want it to go full screen. And then I wanted to start playing that playing is an effect, okay, and then when I click outside the video, I want it to stop playing, which again is another effect. And so I wanted to maybe do a couple of other features later. But we're going to see how we could do this, or how we could diagram this, just so I could show you a declarative way of representing effects. So, over here I have this deeply editor and I'm going to call this video. And so let's describe, you know, just what the expected behavior is going to be. So first, we're going to be in a mini state, and so this mini state is just going to be.
When the video is a small image or something like that, like a thumbnail, and then I'm going to put it to a full state, so full. And so this is when we actually toggle it, so we're going to, you know, click the video, it's going to toggle. It's going to go to full screen. So this is when the video is playing full screen and so we could actually toggle back. And so, I mean, this is a very, very simple representation of what's happening. But so far, we don't really have any effects, we're just talking about the different states. In our little video player, where first we start in Mini and then we go to full and then we could toggle back to Mini. When we click it again. So, when we toggle it the first time, we want it to start playing. So I'm going to, just type play video. And then when we toggle back again, we actually want to pause the video.
So I'm going to add another action over here, and then, you know, this will go back and forth, but we wanted to also do a few other things, so we want to also listen for when we press the Escape key. So now we're adding some, you know, more functionality over here, so if I do key dot Escape, you know what? This should also pause the video, so pause video. But now you notice that every arrow that's coming from this full video state is going to execute the pause video effects. And so instead, we could just make this an exit action. So I'm just going to put this over here, and then we could get rid of these actions over here and over here. And actually, whenever we enter the full states, we want to play the video, so it doesn't matter which event causes that transition to happen. Whenever we're in the full state, we assume that the video is playing. So I'm just going to add this over here and we're going to get rid of this, okay, so our logic is making sense, you know?
When we toggle from mini to full, we're going to play the video, and when we exit the full screen, we're going to pause the video. And that could be caused either. By toggling, or by pressing an Escape key, or actually by, you know, when the video ended? So let's see, video dot ended. Actually, that's an accidental thing, so just delete that state. Okay, so these are in React. These are your fire and forget events, or sorry, fire and forget effects. We're playing the video or we're pausing the video, but we need some synchronization to happen, so we need two things to synchronize. First of all, we need to listen for the Escape key, and so I'm just going to put that here, and we also need to listen for something else. We need to listen for the end of the video. So, now we have our logic. It's in mini and when we toggle it, it's going to go to full.
And then when any of these three events happen, whether we press toggle, press the Escape key, or we in the. Or. The video has ended, then the video is going to both pause and we're going to go back to the mini mode. So we just drew a nice diagram. Now let's get to actually coding it, and actually I'm just going to copy this and my coding is done, so hopefully this works. I have no idea, but we'll see. I'm just going to put this in here. Okay, so now if I press this? Oh, and just to show you, I have this invoke video ended in invoke key Escape. Both of these are going to be listening for those two different things, and we have those right over here. So we have the action specified where we play the video, we have a video ref. And the, you know, HTML5 video API is pretty intuitive.
So we just call dot play or dot pause. When we want to pause the video. We listen for the video ended over here, and we listen for the Escape key over here with no useEffects. Let's see what happens, it doesn't work. Oh, that's because we need our event handler, and remember we're not putting a lot of logic inside of our event handler. Instead, we're just sending in events, that's it. So hopefully, click this, it goes full screen. If I press Escape, it closes, if I click outside, it closes, and also if the video ends. Thankfully. This is only a five second video, it should close, but let's see what happens. So we have video ended, let's see we oh video and did okay, so now if the video ends there you go, it automatically closes and all of that without any coding. So all right, but [Applause] now. So this is why I know this talk is about useEffect.
And, one of the reasons I love state machines is because it allows you to, do declarative effects. But also it allows you to do more advanced logic. So I actually don't like that when the video, you know, when the video ends, it just immediately closes. I actually want to stop this after one second. And if we were using useEffect, we'd have to set up another useEffect for a timer, and then, you know, we'd have to just execute that timer. Only when the video starts playing or if we're in full screen, it just gets really, really confusing. So instead, I'm going to do this. Let's say that, you know, when we enter the full states, we're in the playing state, so the video is playing. And then we have this dot state over here, so we're representing child states of full, where it's either full in the video's playing, or it's full and the video is stopped.
So when the video ended, I'm actually going to move this over here like that. I wanted to go to start and then in the stop state, I actually want to. You know, let's make this after, not 500 milliseconds, let's do one second, so after one second. I actually want this to go back to the mini states. So what's going to happen is when the video ends, we're going to be in this stop state and after one second we transition back to Mini. And I'm also going to fix my typo over here, and then let's get this code and let's, put it back in here. So, oh, I need that. Sorry, I was trying to be lazy. Here we go. Okay, so now when the video ends, it's going to wait one second, hopefully, and then close, all right. So, if you want to see more of this, you know, we have an editor at Steely..ai editor and we.
Actually have a very cool VS code extension over here where you could actually edit your code in the editor. Or edit it, you know, in the code if you wanted to. And so when you add something, it actually adds that state, over here, so we could just type whatever, and that's going to update over here. And it doesn't matter whether you do it here, oh, it's broken, but or here it'll, it'll update for you. And then you could design your states that way. So, you know, you might know that I love state machines. And that's why, you know, I showed that. But also to demonstrate how effects can be declarative.
36:00 When you're fetching data, you should render it as
All right, so let's continue, while I still have a little bit of time. One big thing that you might be using useEffect for is fetching data, so you actually don't need to use useEffect for fencing data. In fact, that's probably one of our biggest use cases right now. Instead, you should adopt the render as you fetch pattern. And so, you know, we might be doing something like this. Where we have a useEffect, we have a fetch call, and you know, you have to do this weird pattern. If you've worked with useEffect and fetching a lot. Or you keep track of if it's canceled or not. And so, you know, instead of all of this, like just making sure it's canceled and then setting the items when you get the promise result. Honestly, just use whatever framework you're using. So if you're using Remix, then you could have a loader function. And so in that loader function, you could actually pre-load that data and then use it directly in your component.
Very, very simple. Next has a very similar approach, too. Sorry with get server-side props, and so with get server-side props. You could get those items and then you could use them actually directly in your store. So these items are here, ready for you to use without any useEffect. Awkwardness. And you are fetching that data before your component is even rendered, which is actually going to be an improved user experience. And of course, there's React query, where I actually really want to emphasize that React query is not a fetching library, it's acquiring and a caching library, that. You know, just really helps you with fetching data. So, one of the patterns I really like actually is called pre-fetching, where instead of executing the fetch when you mount the components, you executed before the component is mounted. At the earliest opportunity you get. For example, if we click this button, we could pre-fetch the items. And now it's available inside of our cache and we can start using it immediately. This, so we're not actually fetching data at this step because it's ready inside of the cache.
There's a bunch of problems. You might be wondering, okay, but I've been using betting and useEffect for a while. There are actually a lot of problems with the approach, first of all, race conditions. If you forget to cancel that fetching when you do something else, or when data changes. It's very possible and likely to have race conditions. Where you might have the second requests data coming in before the first request finishes. Or, you know, even after, and then it's just a very confusing mess. You have inconsistent states and inconsistent data, also you have no instant back button. This is the way that websites work, where if you go to a website, you know you might see some information there, and then you go to another page and then you go back. As a user, you expect to see the information that you were just looking at five seconds ago to still be there.
But when you use fetch in useEffects, that sort of destroys that entire pattern, so you lose that instant. Data showing to the user, not really a good user experience. Also, you don't have any initial HTML content. You might be using a framework that enables SSR, such as next or Remix. But the problem is, when you fetch on in your in your useEffects. Then the only thing that you're going to be rendering to the user on first load is a bunch of loading Spinners every single time. So, instead, use the Frameworks. And, try to fetch that data ahead of time so that you could actually show it to the user when they first render the page. And of course, you're also chasing waterfalls at this point because you might be fetching data inside of the parents and then once that data. Is fetched, you might render a component, then that component needs to, you know, render data as, or, sorry, fetch data as well.
And then that component might, you know, call another component. Which is also fetching data. And that data fetching is not going to start until the component is rendered, which is the wrong model you want to start fetching as early as possible. So, again, the React beta docs have a section on what you should do instead of just fetching data inside of your useEffect. Again, just try to use, they say, use some data library. They probably mean React query here. But, you know, and the final thing, or at least I think it's the final thing. You don't need useEffect for initializing Global Singletons, so instead of useEffect, just call it. The problem with this is that this will run twice, so you could use a ref to sort of prevent that from running twice, or instead of using a ref. You could, you know, just set a variable outside and then that way your store API dot Authenticate function will only run once.
Or check this out much simpler approach just call it outside of your components. Some of you are going to disagree with me, be like, why would you do this? In module scope? This is very bad, and also it doesn't work in SSR. So, yeah, just check if the window is undefined or not, and then call your um. You know, just initialize some method on your Global Singleton, and you might say, Oh, hey, I can't really test using this method. Just put it in a function then, and then you could test it to your heart's content. So, yeah. You don't need to put anything inside a useEffect or everything inside of useEffect, in fact, you don't need to put everything inside of your component itself. So, to summarize, useEffect is for synchronization between different systems. Okay, state transitions are what trigger effects, so when you have fire and forget effects, think state transitions, think what causes those state transitions?
It's probably events, and your event handlers are the first opportunity for you to execute those effects, so these action effects go inside of those event handlers. When you're fetching data, you should render it as. You fetch instead of fetching, then render, and, of course, it's really helpful to model your effects with state machines. If you want to talk to me more about that, I will be around all day. Thank you so much, React Alicante [Applause].
Related talks
-
Goodbye, useEffect
Reactathon 2022. 26:00, 240.2K views -
Goodbye, useEffect
BeJS, 2022. 29:58, 516.1K views -
Goodbye, useEffect (ReactNext 2022)
ReactNext 2022 (Israel). 30:27, 10.6K views -
Using useEffect Effectively
React Advanced London 2022. 24:23, 7.5K views