Video Summary and Transcription
This Talk discusses handling data at scale for React developers, including scaling databases and the need for search. It explores different ways to fetch data in React, such as using useEffect, fetch, and setState. The Talk also introduces Suspense for data fetching and how it improves user experience. It covers controlling React Suspense, handling search, and using render-as-you-fetch. The Talk concludes with a discussion on the RFC status and fetching in event handlers.
1. Handling Data at Scale for React Developers
We're here to talk about handling data at scale for react developers. Let's get more specific with that and actually look at a diagram of what we mean by data at scale. Usually, you have a React app or React UI that talks to an API that then talks to a database. At some point, you're going to experience growth and performance becomes important. So you distribute your API, have multiple APIs, and load balance between them. But if you're successful, your database may become the bottleneck, so you need to scale it.
I was totally playing that guitar. Hi! How are you? Full? Full from lunch? Satisfied? A little more knowledge and information and fun react things? It's like three of you, three of you are awake. Four? Again, how are you feeling? Are you ready to take in some stuff? Off by one errors, you know?
Anyway, Hi! Nice to see you! I'm Tajus, I used to tell people. I used to tell people it's like something, but now I say like advantageous. Anyway, so I'm the director of developer relations at Zara. Look at this beautiful thing. That is my favorite slide and also one of my five slides I have. We're going to be writing a lot of code in this talk and learning properly. This by the way was by Sarah Vieira, she's here, she's doing the last talk today, so catch that if you want to learn how to do 3D stuff. But that's not what we're here to talk about today.
We're here to talk about handling data at scale for react developers. Handling data at scale for react developers. What does that mean? This sounds like a very abstract marketing talk and the answer is because it's not a marketing talk but it is abstract on purpose so that I can change it at the last minute as I always do, okay? But let's get more specific with that and actually look at a diagram of what we mean by data at scale. To do that, we're going to use an amazing tool called Excalidraw. How many of you have heard of Excalidraw? Yeah, if you want to applaud Excalidraw, yeah, for sure. Data at scale. This is what it looks like. Usually, you have a React app or React UI, let's say, right? Is the text okay? Can you all see? Good. I knew. I just asked and what we're going to do is you usually have a React UI that talks to an API that, let's zoom out a little bit, that then talks to a database and these connections usually look a little bit like this. So this maybe oversimplified, but that is most applications. Is this at scale? Probably not. This is a single host database and so on. At some point, you're going to experience like, we're growing and performance is important. So what do you do? You probably will distribute your API. Having a single point of failure is usually a no-no, so what you'll do is you'll do that and you'll have multiple APIs that can fetch multiple times and whatever. And you can load balance between them. And then, OK, you're like, this is cool, but you're going to, if you're successful, what do successful things do? They grow. So if you grow, you're going to be like, oh no, our database is now the bottleneck. Let's make it, let's scale it.
2. Scaling Databases and the Need for Search
So you'll scale your database vertically or horizontally. Scaling vertically means adding memory and disk space, while scaling horizontally involves having a primary instance and replicas. As your data grows, you may notice slow reading times from the database due to disk limitations. To address this, you can add an in-memory database for faster reading, with the option to fall back to the disk if there's a cache miss. Eventually, as your data volume increases, search becomes a common feature needed for platforms like GitHub, TikTok, and Instagram.
So you'll scale it vertically. And this vertical scale usually means adding memory, adding disk space, adding stuff. And it gets quite expensive. You eventually build a supercomputer. Or, if you want to scale your database the other way, you scale horizontally, meaning you have maybe a primary instance and some replicas. So when you get data, it spreads out across the replicas and so on and so forth.
But then you're going to grow more. And we're talking about data at scale, so it's important to establish this context. You're going to grow a little bit more. At some point, you're going to be like, wait, our database is still, reading from it is slow. And that's because usually databases read from disk. Disk by design is not as fast as what? Memory. Memory. So, let's now, this, I've had this conversation, like, at least 50 times in the past week. That's a lie because I'm a public speaker. I really haven't. But you know how it is.
So, you'll add some type of in-memory database just to read from it faster. This will probably be distributed as well. And so now your app will talk to that thing to get data fast. And if it's a cache miss, then you read from the database. Okay? This is close to what things look like at scale. I think Kent C. Dodd's website has something like this in the back. But as you accumulate now data volume, what is the one common feature across things with a ton of data volume? Search. So, GitHub, TikTok, Instagram. Eventually, when you get enough data, you're going to need search. And so now it gets complicated, right? Because your app can read from the search engine, but it's gonna be empty. You're just like... Okay.
3. Handling Data Fetching in React
We'll discuss handling data at scale in React, specifically data fetching. There are three common ways to fetch data in React. The first method involves rendering the component and then fetching the data using useEffect, fetch, .then, and setState. It's important to rely on battle-tested libraries that handle edge cases. The purpose of this talk is to teach you how things work, not to dictate production practices.
Nothing's there. You'll need to find a way to replicate data from your database into your search engine, probably in real time with some type of consistency. People will use a tool like Kafka or something like this. And so you'll send your data there, and this will replicate your data in the search. And now everything's connected. Okay? If you want to take a photo of that, that is a good representation of what most data infrastructure looks like at scale.
Is that what we're gonna be talking about at this talk at React Summit? This is what I want to establish with this diagram. For the sake of this talk, we're going to make everything with a dashed line someone else's problem. This is about React. This is about handling data at scale in React. Okay? That is very important that I tell you that.
So now, I want to talk to you about handling data at scale in React, specifically about data fetching. And so that means, how can we do this? Now, there's something to be said for client-side rendering, service-side rendering, and so on. What I want to talk to you today about is three ways to fetch data in React. This has been talked about a few times. This is nothing new. But before we do that, I need to preface. This talk is about what I've learned and what may be useful for. I think it will be useful for you. But you usually want to lean on libraries that are battle-tested, unit-tested even, that handle edge cases that we cannot foresee. Is that clear? So the purpose of this talk is not you should be doing it this way, use this in production. It's more, I want to teach you how stuff works just so you understand. So we come away with something that we know. So with that, there's three ways to fetch data in React. This is the prevailing three ways. Number one, probably the most common, is you render your component, then you fetch. You have a component, use effect, fetch, .then, set state. This is fairly common. How many of you do that? Have done that at least once. Yeah, OK, the whole room.
4. Fetching Data in React
The next way is fetch, then render. It's arguably faster because you start your fetch way earlier, before your component rendering begins. The third way is render as you fetch, made possible through the new concurrent features in React 18. The React team advises against doing this ad hoc and recommends using a library. Let's just do it now, just once. We'll have an app fetch data in these three ways using Parcel. The app is a jokes app, curated by Shruti Kapoor. For example, how do you comfort a JavaScript developer? You console them.
The next way is fetch, then render. And you see this in some libraries, like NexJS you have like you export get server side props. You'll fetch on the server and then you render your component. There's something to be said for that. It's arguably faster. Why? Because you start your fetch way earlier, before your component rendering begins. And so then as soon as that promise resolves, you set it in state, you're good.
The third way is render as you fetch. This is made possible through the new concurrent features in React 18, and we'll spend the bulk of our time writing code with that specific way, to understand it. But as I said, the React team is very clear, don't do this in an ad hoc way but use a library. It's for the best. That said, let's just do it now, just once. So with that, that's my last slide. Let's just code. I like coding. Inshallah, the internet works.
All right, so we saw the diagram. What I want to show you is an app. We'll have an app fetch data in these three ways. The app, let me just start my dev server here. The app is, we're using Parcel, just because for me it's really great for demos. Oops, src slash, sorry, it's yarn parcel, src slash index dot html. This is going to bring up our app. And what we have is a jokes app. So these are developer jokes, classic. Queued by the one and only Shruti Kapoor, by the way, shout out. She's a really valuable member of the community and the team. And if you don't follow her, you shouldn't. The reason she's on this is because she curates a collection of developer jokes. For example, how do you comfort a JavaScript developer? You console them.
5. Fetching Data in Three Ways with React
We'll fetch data three ways in our React app using Create Root. The jokes component is supposed to fetch data but doesn't. We'll get a code snippet in JavaScript to fetch the data client-side. We'll add a filter to search for jokes and set the joke to the result records. This is a common way of fetching and rendering components in React. We haven't addressed loading states yet.
Okay, so I just stole it from here. So what we're going to do real quick is fetch data three ways. We'll do it the way we all know first, so our app. So we have a React app using Create Root, it's a new thing. We have our app component that renders, as you can see, the actual elements here, the heading, the jokes, and so on. And lastly, we have a jokes component, this thing, which is supposed to fetch data, but doesn't. So we'll fetch data three ways and then we'll talk about what we learn.
To do that, I'm going to get my data from here and fetch it immediately. Again, inshallah, network, please. Awesome, that's enough. I think, you know what I think? I think the network depends on... Okay, nevermind. I was gonna do something awesome, but now you don't.
Okay, so I'm gonna get a code snippet here in JavaScript to fetch this in my app, just client-side, as you know. So we'll do something like this. And when search changes, just refetch. We'll paste the code snippet. I'll add a filter, just for fun, where the joke contains search. And then instead of console logging the response, I will set joke to result.records, okay? I'm just fetching data. You're familiar with this. I'm not spending too much time on this. And just like that, we have jokes from an API. So what is the most used language in programming? Profanity. Ha ha, it's actually funny. Does the search work? I can use words like okay feenot. But okay, married, life of developer, wife right, 100%. So we're fetching, we're rendering the component, then fetching. This is fairly common. If we walk through the code briefly, we have the jokes in state, we fetch, and we set state, and then everyone's happy. Notice, we're not handling loading states yet.
6. Exploring Different Data Fetching Approaches
We'll discuss the traditional way of fetching data in React and explore the fetch, then render approach. By starting the fetch early, you can reduce load times and avoid network waterfalls. Another approach is render as you fetch, which utilizes concurrent features in React 18 to render components that are ready and fetch data as needed.
We'll get to that. This is the traditional way. What about fetch, then render? You see this less common in Userland. I've spoken to some of you and you're like, what is that? Essentially, the gist of it is, you start fetching early, so that your load time is reduced. And this helps if you're loading a component with React.lazy, and you're importing it dynamically, then as soon as the component is imported, it fetches immediately and then renders. This is actually fast. And in our case here, we have 20 minutes, so we're going to be working with one network hop, but in cases where you have multiple, this really helps you avoid waterfalls, network waterfalls, meaning you have one request, you wait, you have another request, you wait, and it's this waterfall.
This is render then fetch. Let's do fetch then render. So what we're going to do is we're going to take this whole code snippet thing out of use effect and put it here in module scope. And you're like, how can this be? You don't have set jokes. Exactly. So I'm going to take this piece, put it back in use effect, and do promise.then set state. What is promise? It's my fetch call from module scope. Okay. Does this look odd? Maybe, because you haven't seen this that much. So we don't get the dynamicism, whatever, the dynamicness of the search prop here. So because we're fetching in module scope, does it work? It does, and it's arguably faster. Why is it arguably faster? Because we're fetching before we render. So the data is kind of ready. The problem with this, of course, is it's just going to be stale. I can't control it with props. I can maybe if I made promise like a function, like get promise or whatever. Sure. But it's not that common, especially if you're outside a library and the performance benefits are, I don't know, questionable.
Let's talk about render as you fetch. Okay? React 18 has concurrent features where you can start rendering a component and when you reach a component that is not yet ready, that doesn't yet have data, React doesn't render it. It renders like a hole, a fallback, and after that it continues down the tree. And then when the component is ready, then it renders. So it's like, render as much as you can, fetch while you need it, and then render again.
7. Understanding Suspense for Data Fetching
The tool that enables this is called Suspense for data fetching. Learn how it works with examples. Create a resource using the createResource function. Set the result and status states. Update the scoped state when the promise resolves.
That's what we look at. The tool that enables this is called Suspense for data fetching. There's an RFC about it here. Trust the RFC, don't trust me. This talk is just condensing this with examples, but this is the source of truth, and so is the React blog and the React docs.
Specifically, I wanted to show you Suspense and Data Frameworks. This is important. Learn how stuff works, or maybe don't do it yourself. This is just for understanding.
Now, how does this Suspense for data fetching work? Let's look at an example here. So we're already fetching in module scope. What I want to do is create something called a resource. It's kind of like a primitive that Suspense for data fetching will use, and this is what they look like. I'll have a function called createResource. I'll wrap my entire thing outside of my component in it. Okay? I'll need two pieces of state. So I'll need the result, which can be anything. This is TypeScript. And I'll need the status, which is, in the beginning, it's initial. So I have a bunch of boilerplate here. I'm not touching that. What I can do is promise. Actually, I'll just add a dot then here, and by now I have data. So data, and I'll set my state. Result is data.records, state, status, state is done. I'll do the same thing for catch. So .catch. State is error, and the result is, in this case, it's not even data. Let me just fix that. Okay, so when the promise resolves, we're going to update our scoped state in this function.
8. Understanding createResourceReturn Function
The createResourceReturn function returns an object with a read function. Depending on the state, read throws a promise if the status is initial, throws the result if the status is error, and returns the result if the status is done. React handles these cases.
What does this function createResourceReturn? It returns... It can really return whatever you want. But in this case, we're returning an object with a function called read. And what read is going to do is if the state maintained in this function is initial... I can use a switch case for this too. I'm not doing that just because I don't want to. If the status is initial, so the data hasn't loaded yet. This was controversial, so I'm throwing the not yet resolved promise. Who's going to catch it? React. And then when it's ready, React will continue render. If the status is error, we'll throw the result instead. And if the status is done, did I write done? If the status is done, I just return the result. Return the result. And so React knows how to deal with this. This is what they handle. Okay?
9. Improving User Experience with Suspense
And instead of all of this set state stuff, all of this, instead of jokes here, I'm just going to read from my initial resource like that. So what's the benefit of this? It's instant loading state. Throttling the network request shows the app appearing when the jokes part loads. To improve user experience, we can wrap just the part that needs data in the suspense component from React.
And I will just create it just like that. Okay? And instead of all of this set state stuff, all of this, instead of jokes here, I'm just going to read from my initial resource like that. Save. Let's go back to the demo. And it works. So what's the benefit of this? This is great. There's some benefits.
For example, it doesn't replace... Well, it doesn't actually search. We need to figure that out first. Right? But look at the loading state. It's instant. There's no, like, flash. More than that, if we throttle the network request, just to make... This backend is way too fast. I don't even know what it is. But let's throttle this instead, if I can... Yeah. So let's throttle this here. And now... Let's actually throttle it a lot. Let's do, like, three seconds. And now what we'll notice is we have nothing for three seconds. And the whole app appears when the jokes part loads. This isn't ideal user experience.
So instead, what we can do is go to our container app and wrap just the part that needs data in the suspense component from React. And now if we load the page... Wait, wait, wait, wait, wait. Three seconds. Boom.
10. Controlling React Suspense and Handling Search
We can granularly control where React suspends and choose different parts of the DOM to hide. Suspense works on the server side without code changes, pausing HTML as it's downloading. To make the search work, we'll use an effect to recreate the resource when the search changes. This ensures that the resource fetching data changes accordingly. However, there may be an issue with the access token expiration.
Boom. So we can granularly control where React suspends. We can even give it a fallback here, just like that says loading, for example. And now if we reload, we have loading where we want it.
But with suspense we can actually choose different parts of the DOM to hide. So we moved it, we now hide the paragraph. We can also hide the input field so you don't type and then it loads. So that's suspense. This by the way also works on the server side, out of the box. No code changes. You shouldn't implement it yourself, trust the library, but suspense on the server side works exactly like this. The HTML actually pauses as it's downloading.
The last thing I want to show you is now this doesn't work, actually let's make the search work. So we're already here. What we need to do is we'll use an effect such that when search changes we'll recreate the resource. So we'll do resource, or just R, and setR. And we'll use state initial resource. That is this. And so now we'll use this instead. So when search changes we'll setR to search as a parameter. And our create resource will accept a search, which is a string. And search will be replaced here with search. Just like that.
This looks great. setR is, it needs a resource right, so we create a resource in here. And so now, every time the search changes, the resource that fetches data changes and our search should work, but it could be that my, yeah, my access token expired. I need a new one. The last 10 minutes so that you can't sniff them and steal them, so let's go back to my fetch call here and replace this thing. Okay cool. And now, oh.
11. React Data Fetching and Updates
We need a way to tell React what is an urgent update and what can wait a bit. To do that, we use another concurrent feature called use transition. This allows us to more fine-grainedly tell React what is important and what can wait. We can also decide where the loader occurs with suspense, using the render-as-you-fetch approach. These considerations are important when working with data at scale in React.
I'm doing something wrong, aren't I? Inshallah the network isn't working again. Okay it's 400. Right. Sorry, I meant joke contains search. Oh, thank you. Whoever said that, I appreciate you. There you go, default prop and now it should be on the money. Okay, there we go, but there's a flash. Look, so now if I try to search this thing, if I type like W, ah. Hey! So what about, what about I. You hide my, ah. So look a keystroke is an urgent update. Changing results is not an urgent update. We need a way to tell React what is an urgent update and what can wait a bit. Okay, to do that we use another concurrent feature called use transition. This is a hook and this is really important so pay attention. So you get back a tuple loading and start transition from this hook, use transition. What we'll do is we'll wrap this set state of the resource in this. And just like that, React now knows, I'm gonna wait for all the urgent stuff and then I'm effect. So let's try this again. Let's type profanity, look at that, wow, I can type all I want. And then there's like a three-second delay and then it changes. So that allows us to more fine-grainedly tell React this is important. That can wait. We can also, if we recap, more fine-grainedly decide where the loader occurs with suspense. And that is render-as-you-fetch, where React will actually pause where the data is requested and continue down the tree and then when the data is ready, come back and render there. These are considerations you're going to have when you work with data at scale in React, why? Because it can muddy up your UI and introduce jank. All right, let's recap and finish. What have we learned? We've learned about the three ways to fetch data in React so far. Render-than-fetch, fetch-than-render, render-as-you-fetch.
Using Render-as-You-Fetch and Q&A
We looked at them in practice. We also looked at data infrastructure at scale. Now, the last question: how do we use this stuff? Trust the library, like Next.js or Remix. Lean on the shoulders of giants. Thank you for having me on the stage. We have a few questions from Slido. Could you use memo over resource replacement when the search string changes? Is there any similar option to do render as you fetch before React 18?
We looked at them in practice. We didn't get time to look at it on the server side, but that's a 20-minute talk. But render-as-you-fetch also works on the server side. We also looked at data infrastructure at scale. And I don't know, I feel like it's been good.
So now, last question, how do we use this stuff? You don't do what I showed you here. This is just for understanding. There is a library. Trust them. Next.js. Remix. Or framework, I should say. You usually want to lean on the shoulders of giants, as we all do. As Taz said, community is everywhere. And with that, I want to wish you happy coding, and thank you so much for having me on the stage today. one well-deserved applause. Did you know that I once wrote a whole software to make it look like I'm good at live coding? And you're actually doing it better than my fake software, so that's incredible.
All right, we have a few questions from Slido. So let's get right into it. And also, by the way, here in this room, if you are moving between tracks, could we do so quietly so the back of the room can also hear the questions? Thank you very much. All right. Could you use memo over resource replacement when search string changes to avoid double renders? Probably. I don't know. I haven't tried. I encourage you try and let me know. Cool. Is there any similar option to do render as you fetch before React 18? As far as I know, no. I mean, in React, there was some experimental builds before React 18 that you could do that. But concurrent features are new. The 18 part is because it's a breaking chain, so to speak.
RFC Status and Fetching in Event Handlers
So all of this stuff that you talked about is in the RFC and documentation. The status of the RFC is more intent to ship instead of shipped. Fetching in an event handler such as onclick to navigate is fetch then render, not render as you fetch. These are all the questions we had from Slido.
So I don't think so. So all of this stuff that you talked about. It's in the RFC. It's in the documentation. Right. Exactly. What's the status of the RFC now? Is it ready for production use? I think it's more intent to ship instead of shipped. Right. But the intent is there. Okay. Cool.
What about fetching in an event handler such as onclick to navigate? Is this render as you fetch? Could be. Yeah, I think. I don't really know. It's fetch then render. Thank you, Philip. He was in my workshop. He knows stuff. That is, so onclick in an event handler is fetch then render. So no. All right.
Well, I think these are all the questions that we had from Slido. Awesome.
Comments