Video Summary and Transcription
This talk discusses the best practices for fetching data during the initial render of a component in React. It emphasizes the importance of fetching in advance and avoiding fetching twice. The talk also highlights the need for an external cache to store information about API calls and the use of a cleanup function to avoid memory leaks. Additionally, the speaker mentions their library, react-disposable-state, which can be used for making side effects during render.
1. Fetching Data During Initial Render
In this talk, I'm going to discuss how to fetch data during the initial render of a component. Fetching during the initial render is preferable to fetching in an effect. Fetching in advance is better than fetching during render. Sometimes, fetching during render is the best option. Fetching is just an example of a side effect that should be performed only once and must be cleaned up. We want to avoid fetching twice and instead reuse the same network request. We could perform other side effects like firing off analytics or crunching numbers on the server.
♪♪ In this talk, I'm going to discuss how to fetch data during the initial render of a component. But before we get to how to fetch during render, we should first discuss why. Why do we want to fetch data during render? Well, we fetch data because we need it to show the user something useful. Duh. But why make the network request during render? Well, the sooner we fetch, the sooner we can show the user what they want to see and the better user experience we can provide. So fetching during the initial render is preferable to fetching in an effect, which necessarily occurs after a component initially renders, sometimes far later.
But is that the best we can do? What about fetching in advance? Consider a button that, when clicked, shows a modal, which needs data. We could start the network request when the user clicks that button, meaning that the network request will start before the initial render and we'll be able to show the relevant content to the user even sooner. That's awesome. Okay, so fetching in advance is better than fetching during render. So why fetch during render at all? Well, in some cases, it's the best you can do. Consider a modal that is shown based on some opaque function of some hard-to-reason-about redox state. Basically, we don't really know why this modal is shown or under what conditions. And in situations like that, it might be difficult to determine an appropriate moment to start that network request. So the best we can do is to fetch during render. As an aside, nothing in my presentation is really about fetching per se. Fetching is just an example of a side effect that should be performed only once and must be cleaned up.
Now, the cleanup we want to do for fetching is to garbage collect the data we received from the network if the UI no longer needs it so that on low-end devices, we avoid running out of memory. But more generically, if a component renders twice, we want to avoid fetching twice and instead reuse that same network request. So another side effect that we must perform is to know somewhere that we've already made an identical network request. And the cleanup we want to do is to, after, let's say, 30 seconds, remove the item from the cache because next time we render that component, we do actually want to make a network request. So what are some of the other examples of side effects we could perform like this? Well, we could fire off some analytics. We could have the server start crunching some numbers we're going to need later. Those are pretty much everything I'm gonna say about fetching during render applies to those as well.
Okay, so now we can finally get to how to fetch during render. Let's keep it simple. Can we just make the darn API call during the render function? Well, unfortunately, React and Cloud Components render function multiple times. And on the second render, we'd really like to reuse that previous network request. So can we use hooks? Well, unfortunately not. If your component renders, suspends, and renders a second time, all hooks will be created anew for the second render.
2. Making Side Effects During Render
We cannot use state or refs to store information about the API call. The fact that a network request exists and should be reused has to be stored in something that outlives the render function. Making side effects only during the initial render requires an external cache. The cache should behave in a way that clears and disposes the item after a timeout to avoid memory leaks. If a component renders and mounts, it should not be garbage collected, and React will execute a cleanup function when the component unmounts. With these three principles, you can safely make side effects during render. Check out my library, react-disposable-state, on the Isograph github repo.
So we cannot use state or refs to store information about the API call. So the fact that a network request exists and should be reused has to be stored in something that outlives the render function. Which could be props, context, or a global object. This leads us to our first principle. Making side effects only during the initial render requires an external cache.
Okay. So let's discuss how this cache should behave. Consider that modal. We render it. It suspends, meaning that React calls its render function, but does not modify the dom to show the component to the user. Then, before the component commits, the entire tree unmounts because the user navigates to another screen. In this situation, React will give us no indication that the component will never mount. So when we initially place the item in the cache, we had best also set a timeout that clears the cache and disposes the item, perhaps, after 30 seconds. Otherwise, in situations like that, we'll have memory leaks.
Okay then. So what happens if the component renders and mounts? Well, it may continue to render afterward, including after more than 30 seconds have passed, and the component will still need access to that data. So it really shouldn't be garbage collected. But lucky for us, if a component mounts, React will necessarily execute a cleanup function so we don't need to rely on a timeout to clean up the item, meaning that an item should not be cleaned up while a mounted component references it, but instead, when that component unmounts. Okay. So with these three principles, you can safely make side effects during render. I have a library, react-disposable-state, under the Isograph github repo, where I expose extremely generic APIs for making side effects during render, and so on. I hope you check it out. Thanks.
Comments