skip to content

React Suspense in GraphQL with Apollo Client

Learn how to combine the latest in GraphQL and React Suspense to build apps that feel great to build AND to use. Lenz Weber-Tronic will teach us how it works.

Full Transcript

Click to toggle the visibility of the transcript

Captions provided by White Coat Captioning ( Communication Access Realtime Translation (CART) is provided in order to facilitate communication accessibility and may not be a totally verbatim record of the proceedings.

JASON LENGSTORF: Hello, everyone. And welcome to another episode of Learn With Jason. I'm Jason. And I'm superhappy to have you here. Today's episode is going to be a lot of fun. We are bringing in an influential character, Lenz WeberTronic. How are you doing, Lenz?

LENZ WEBERTRONIC: Hi, everybody. I'm doing well.

JASON LENGSTORF: For folks who maybe aren't familiar with you, do you want to give us a little bit of a background?

LENZ WEBERTRONIC: I'm a web developer. Five years ago, I got into open source. I've been on the Redux team so I've been working a lot on the Redux Kit and the creator of, which was inspired by Apollo Client and one year ago, I started working at Apollo GraphQL as a maintainer of Apollo Client. So, everything goes fullcircle, I guess. [Laughter]. One thing I want to add is, just to give this a little bit of publicity, I do have ADHD. A lot of developers out there have, a lot of developers don't know they have. If you suspect you might have it or know somebody who may have it, I have a talk on having ADHD as a developer on GitNation. Could be something interesting. I think it's all the visibility it can get.

JASON LENGSTORF: I'm going to find a link to this and� Dealing with ADHD as a Developer, there we go. I'm going to drop a link to this in the chat. All right.
So, that's a good point of visibility to go into. So, you've sort of been working on a lot of code that I think a lot of us use daytoday in our work. You mentioned Redux, you mentioned Apollo Client, RTK Query. These are pieces of code that� they are featured pretty heavily in production work and so I guess, what led you down this path? How did you end up in a position where you're maintaining these kinds of projects that are backing such large codebases?

LENZ WEBERTRONIC: Honestly, it's creepy if you think about how many people use that code. Um, it started out like every time you want a feature in an open source project and it's not there and you start poking the maintainer and the maintainers are like, hm, yeah, I don't know, sounds interesting, I have no idea what you want to do. Open a PR and then you start opening up PRs and after a while, you're kind of part of the project. That happened for me, first, with Fork TS Checker. It created a second process to do the typechecking and I wanted typecheck Markdown files, which never happened in the end, but in the end, I was a maintainer of that thing and one year later, the same thing happened with Redux Toolkit. I wanted to have nicer user experience and at some point, you're an open source maintainer, you talk with everybody else in the ecosystem and, like, everybody brings in their weird ideas and their vision and things happen. It's pretty natural. I'm not sure if you can really plan for that.

JASON LENGSTORF: Yeah. So� so, to� to, I guess, paraphrase, you� you were using these things and then you� you needed something that led to you opening a PR and just sort of naturally progressed into you becoming a maintainer?

LENZ WEBERTRONIC: Yeah. The more you use something, the more you see, like, where something could be nicer and I'm a strong believer, if you can make something better, you don't just keep your local branch, you try to commit it back. I know that local workaround is probably a half an hour of work and getting it back upstream is probably two days of work. My argument is always, if I have it only local, I have to maintain it. If I get it upstream, someone else has to maintain it, which usually pays off and it also helps a lot of people in the end.

JASON LENGSTORF: I see this philosophy started out well, if you get it upstream, somebody else has to maintain it, but it kind of backfired on you. [Laughter].

LENZ WEBERTRONIC: Now I get the pull requests. You get in� you see that someone put a lot of work into it, but now you're on that side where, like, yeah, but if I have to accept that, I have to maintain it and it might not always be the right direction for the project. It might add distractions. It might add APIs that lead to adverse developer experiences for other user because you come in there, you see ten different ways of doing something and two of them are pretty optimal and eight of them will be like� you shoot yourself in the foot after a while. So, getting that balance right, from a maintainer perspective, of accepting PRs, steering PRs, getting people to make talk through PRs before they are opened, that's a really interesting part of that work.

JASON LENGSTORF: Absolutely. Yeah. Somebody, on Tuesday, on my solo stream, made the comment that, you know, most code problems are actually people problems in disguise and I think that what you're talking about feels very similar. You can solve a problem really quickly but the challenge is, the particular solution, it has these followon effects and it changes how people work and impacts how things in the codebase function and being able to communicate about that and talk through it and help everybody understand, I know this change would solve your specific problem, but here are the other things it would break so that's why we can't do it in the way it's implemented. Can you make a shift for me to incorporate this thing or that something? They are challenging and an undervalued skill set.

LENZ WEBERTRONIC: There's also [Indiscernible] problem, is what they're called. Someone comes to you, I want to do X, how do I do X? And you start asking questions and after a while, you figure out that they were, like, uh, asking how to put a screw into a wall with a chainsaw, not because they wanted to put a screw into the wall with a chainsaw, but they were in an empty room and they didn't know where the tool cabinet was so all they saw was a chainsaw and they tried to use that one tool that they had to do something that could have been done a lot more elegantly in another way but they don't tell you. They're just like, I have these two things, I need to get them in the wall and they� they won't tell you why they want to do it, where they're coming from, what they already tried so a lot of times, even if you get a PR, it might be a PR to enable a feature that could be done a lot easier if you wouldn't haven't already gone down that rabbit hole. Seeing that early, it's a nice challenge.

JASON LENGSTORF: Absolutely. Yeah, I think that is� I mean, you've just encapsulated so much of the open source experience, I think, putting a nail into the wall with a chainsaw, that's going to live with me for a long time. [Laughter]. Okay. So, today, I mean, there are so many things that you could talk about, obviously, as a core maintainer of Redux, you've done a lot there. We've actually had you on the show for Redux in the past so I'm going to put a link to the Redux topics, if you want to hear about Redux from Lenz and the other Redux maintainers.
Today, I want to talk about Apollo and I want to talk about React Suspense because both of those things I know are useful. And I've seen very cool things built with both technologies, but when you brought it up, you brought it up as, like, here's how you should combine these things to get a really good experience. And, like, when you said it, I was like, oh, I guess it does make sense they would combine. But it never occurred to me before to put Apollo and Suspense. I figured they were parallel technologies, not complementary technologies. You would use one or the other.
Okay. Before we talk about how they combine, maybe we do highlevel. Can you talk a little bit about what Apollo Client is?

LENZ WEBERTRONIC: Apollo Client is a library, like� or a caching library. We get into that a little bit later. So, like, React Query, RTK Query, Relay or Oracle, they try to give you a tool so that you can query an API from your components, essentially. The thing about Apollo Client is, it's specifically made for GraphQL, so it can make assumptions about the transport layer that other clients that are not made for that cannot make. And, they can also make assumptions about the data structure that otherwise would not be possible.
So, because GraphQL has a very specific structure in the responses, we can actually make use of that and normalize everything.
And that's extremely useful because it means that your UI will be [Indiscernible] if you have the same data from three, different sources in your UI, it will always point to the same normalized data point.'s extremely easy to� to enable that for GraphQL, but it's borderline possible to do that with a REST endpoint. You have to essentially write the logic for that yourself. There's no guarantee how it's shaped or how it delivers data for you. You have to do it yourself and then you end up writing a lot, a lot of code. With GraphQL, we essentially get that for free.

JASON LENGSTORF: And so, this was a big reason why, way back in the day� in 2015ish� I got really excited about GraphQL� was it 2015? It might have been later. When I first started at IBM, we had this very complicated data problem. We had dozens of teams, all of which were exposing REST APIs and every team had to try to communicate to every other team about what was changing. Some were using the OpenAPI spec, some weren't. There was no normalization. So the other problem we had is because of that, they didn't, like, promote a single source of truth. It was more of a, hey, tell us what we need and we'll make you a bespoke endpoint so then each of these services not only had their baseline endpoints, but a lot of extra endpoints that were subsets of data and there was just no way of knowing how to keep this stuff consistent.
When I started looking at GraphQL, the thing I found that was really exciting about it was this idea that anybody using GraphQL can create their own bespoke endpoint from a REST endpoint. You say, I want these fields and only these fields and that's what it gives you. From a provider standpoint, if I'm the maintainer of the GraphQL API, I have perfield analytics on what people are requesting so I can see whether or not somebody is using this bespoke data. If there's a really expensive field and nobody ever calls it, we can� we can safely deprecate that. We can prove it with data. With REST, I have no idea how you would ever prove that, short of a full code on it. This really got me excited about GraphQL. And what you just said about the normalization and the way Apollo Client can do caching and predictability. The other neat thing about GraphQL is this concept of, like, you know what the shape of the query is because you're defining it very clearly. You know exactly what data you need. It's really easy now to say, these queries call the same data so they can be deduped. These queries request that that field, they can be invalidated. That's just really, really hard to do in REST.

LENZ WEBERTRONIC: And the nice thing is, you don't even need to invalidate that. You can just, like, get� get that new entity back from the mutation and will automatically merge into the result you already have in the cache so you don't need to do another outgoing call.

JASON LENGSTORF: Really? It's been a while. I'm not going to lie. It's been a while since I've used any of the GraphQL tooling. So that's really cool. [Laughter].

LENZ WEBERTRONIC: For API, it's absolutely true, too. API, you need someone who has a little bit of an overview of what's happening there, but with something like Federation, you have a lot of teams that publicize their data and you might have, like, a billing endpoint that just says, okay, on the user type, just add this billing information and they don't know where that user came from, what the first name of the user is. They just know the billing information. They publish that and it gets merged into the main schema of your company and you have that team working on its own without having to talk to everyone else all the time and that's supervaluable.

JASON LENGSTORF: I think you just nailed a very specific pain point of working atscale, which is this necessity to keep very constant, highcontext communication with everybody in the company. I think that's a really big challenge in code because codebases are too big for everybody to keep full context and this idea of, not saying, hey, teams, don't communicate, but making very clear� you know, talk about it as an API boundary, as an SLA, whatever it is, where you're saying, my team will guarantee that these surfaces are consistent and if they're going to change, we will communicate about these surfaces. Everything else doesn't matter. What we're doing behind the scenes, you don't need to care about unless the case of you're maintaining the user theme. Otherwise, I don't have to care about the user at all. I know I can use that as part of my, like, result set.

LENZ WEBERTRONIC: And all you need to know is, like, there's a type that is named "user" and it has an ID. That's all the information you need to stay in touch with the user team.

JASON LENGSTORF: So, yeah, it's so good. And I think it's easy when we're on smaller projects, to sort of look at something like GraphQL and say, that's a lot of setup. And you're right. But, the tradeoffs, as you grow, and as you scale, are� it really is one of those things, with complicated data and lots of teams maintaining lots of different aspects of the data, I don't know there are really better ways to solve that problem. I think GraphQL has a unique value prop.
Okay. So, Apollo Client, really great way to interact with GraphQL data. GraphQL, great way to work with complex data and give people a lot of control over the data they're giving.
So, what is React Suspense then?

LENZ WEBERTRONIC: React Suspense is essentially a mechanism to React for fork. It can do asynchronous operations in the background, wait for them or you prerender them to get them in fast. So, the thing is, usually that's� nowadays, used with a router, like, the [Indiscernible] router in Next.js, for example. So, when you click on to the next route, it doesn't immediately switch you over and you have a big loading spinner and you don't see anything. But it starts what they call the transition, which means you still [Indiscernible] UI rendered. Once enough of that is ready, it will swap over.
And, that's something that also lends itself very well to data fetching. I think the first few examples that [Indiscernible] showed in his conference talks were about data fetching, like, things you have three components that all three of them fetch some data. They don't finish at the same time. They all have their own loader indicator. You have a spinner here, you have a spinner there. Something pops up here and it's spinning, over here, something else pops up. And at some point, all your data pops in. And in reality, that's, like, halfasecond of epilepsy. You don't want your UI to look like that. You'd much rather want to say, like, this is an area of my UI that should pop in together. If there are three things loading, then just wait, in the background, until all of them have loaded and then switch in the new layout. You could do that by manually� you transform that information that something's loading, you show one, big spinner but that's really nice, either.
With Suspense, instead of showing that one, big spinner, which is possible, you could also keep the current UI mounted until the rest is done and then it switches over.
So, Suspense has a lot of interesting ways of getting this� this asynchronous. It says, I'm not ready yet, I need more time and then React does something with it.

JASON LENGSTORF: Nice. And if I remember correctly, there's kind of a clever mechanism being done, if I remember correctly, to make Suspense doing, where we're doing things that kind of don't feel right. Are they still throwing promises and things like that?

LENZ WEBERTRONIC: They were throwing promises, um, that has been the old way of doing it. The new way of doing it is you call the "use" hook, which is part of the Canary release. It might throw a promise or something like that. Realistically, that's the only way we can interrupt code flow. The next line of code will be executed, which expects data to already be there and it probably isn't. You have to interrupt things.
But no user should throw promises in the code to Suspense. Also no library should really do that. We� kind of have patches in Apollo Client. If you use the latest stable version of React, which is 18.2, then it's not there yet and you want to use Suspense. And there are many things around that, that also mean that you don't want to do any of that by hand. When� when you start that stuff with suspending, your component never mounts so it never� until it's done. So, it never has state. So you can't just keep that promise in state. So you need to keep that promise somewhere else. That exists outside of your component lifecycle and it might� the component might never use it or the component might remount and progress something different and you have to do a lot of management there and you don't want to do anything like that in user land.
So, it is up to data fetching libraries to manage that for you. And, at the beginning of last year, we� we had a video with the React team, theoretically, all of that would have been possible for quite a long time, but in the release notes of 18, there was, like, one, small paragraph: Please don't use this for data fetching yet. [Laughter]. was there, but� that was� that appealed to the community to not do it and we didn't for, like, a few years and we talked to the React team and they were like, okay, all the problems we have foreseen are taken care of, you can try a round with this now. And for Apollo Client, that meant that, I think around October, my colleague started playing around with it, October 2022? And, in July of 2023, we released, um, Apollo Client 3.8, which had suspense capabilities.

JASON LENGSTORF: Nice. Okay. So, uh, very good caveat here� and also, I just� you made a comment about you never want to manage in user land. I just want to say, I'm very glad that teams like you are willing to managing things like this because I don't want to manage this any land. [Laughter]. I'm very happy I have never had to think of any of those concerns because there are libraries considering all the different edge cases.
So let's talk about how these two things fit together. So, you said you had to kind of patch Suspense into Apollo Client to get it to, you know, be on stable React without switching of to the Canary release. So, how, like� as a user, how should I be thinking about the combination of Apollo Client and React Suspense? Is it just built in and I shouldn't think about it or are there ways I should combine it?

LENZ WEBERTRONIC: There are things that you have to think about. If a component suspends, it suspends the parents up to in next suspense boundary. You have to know you're using Suspense and it's a very explicit decision on your part because you're not using the normal hook, but one of the new hooks, like Use Suspense Query. And, you have to be aware that if you don't put Suspense boundaries in the moment, your whole application will suspend and you probably don't want that.
So, the moment you start using these components, you get to the point where you will analyze your UI, where does it make sense for the user experience to put a Suspense boundary? And, you also get to the point where you need to learn what a transition is because sometimes you want Suspense to fall the whole page back to a loader spinner and in other situations, you might want your page test to remain how it was before, until Suspense is done. The user might even still interact with the old page while the new one is rendering.
That's up to you in that moment. So, you need to get a little bit into that mindset of, okay, I� I have [Indiscernible] reactor right now, which is superweird. [Laughter].

JASON LENGSTORF: As you were talking through that, I felt my brain starting to melt a little bit, which I think is a good sign to start looking at code. So, why don't I switch us over into Pair Programming View, which I'm going to do, here, and then I need to share my screen... this one. All right. And hide this little banner...and unhide this little banner. Look at us go. All right. [Laughter]. So, this is� we're talking to Lenz today. You can find Lenz on the� the old Twitter. And, go check that out. We are going to be talking about Apollo Client, so here's a link to Apollo Client. Um, I didn't put up a React, so this one looks like it'll be good. Here's a link to React Suspense. And, uh, from here, if I want to give this a shot, what's the� what's the first thing I should do?

LENZ WEBERTRONIC: The first thing is, we take a look at the API we have. So, later we know a little bit what we're working with. So, I've given you, earlier, I've given you that Explorer link. Yep, that one. And, this is the API we're going to work with. This is a dataset that's called Pagila. I hope it's set that way. Which is a test dataset for MySQL, it's nice because there's a lot of data in there we can play around with. This is, like, a madeup movie chain, where you can rent movies, if people still remember that. So, you� we can look at the stores. We can look into each store, which movies are there. We can look at each movie, which actors are there, who rented the movie the last time. We can just look around a little bit there.
So, people who maybe don't know GraphQL get a little bit of a feeling, what GraphQL actually is because first and foremost, this is, like, a query language.


LENZ WEBERTRONIC: I would say we can maybe start with, um... "all films," for example.

JASON LENGSTORF: "All films list." Is everybody watching�

LENZ WEBERTRONIC: Button on the left.


LENZ WEBERTRONIC: Add the description, on the left.

JASON LENGSTORF: Add the description. And I'm just going to clear this stuff out.

LENZ WEBERTRONIC: Yeah, clear that out.

JASON LENGSTORF: For anyone who's never seen this before, look how cool this is. This is what's happening, we're looking at the schema, itself, is generating this documentation. Like, you didn't have to code this up. You just� you know that because of the way GraphQL is written, that these documents will be generated correctly when you put it into the Explorer. So, this, here, is just the code generated a superhelpful UI that allows me to go in without ever having seen this before and I can pretty quickly look at it and say, yeah, I want the rating. I want to also find out what the title is and then I can run this. Is this correct?

LENZ WEBERTRONIC: Yeah, that's correct. It's just making doublesure that you know what you're doing. [Laughter]. We are currently querying all of the films, so it's probably a bit slow. We might do something like, first 50. It's a big dataset.

JASON LENGSTORF: Oh, yeah, good call. We can immediately do that by do this, first, here. I go into my variables. [Laughter]. I'm all zoomed in here so I got to do the thing. So we can get� you said 50. So, I say 50. And that now limits the number of films we get back so I can show that more obviously if I make it 10.
Like, how freakin' cool is it that I've never used this API, but because I've seen a GraphQL Explorer, I can navigate this database. That's very cool. And I've never used this version of Explorer before. I think the last time I used it was three or four years ago. I'm superexcited to see how good this looks.

LENZ WEBERTRONIC: There are also, like, five different versions of Explorer out there. [Laughter].

JASON LENGSTORF: Yes, there are.

LENZ WEBERTRONIC: And I don't know how to use half of them. [Laughter]. I don't do that a lot. But, yeah, here, we just created a little query that gets us all the films and then, yeah. That's essentially what we did without knowing anything about the API. And the nice thing is that we now could take this query and move it over into our React application, just by copypasting it. And then, we would have access to all of that data, um, over an empty application. So maybe we start and we just make a little appropriation that shows a list of films.

JASON LENGSTORF: Sure. And� and, the other nice thing here is we can say "get all films" and now it's going to tell me the name of the query. So, I have my query here, standing by. And I don't need to save. I wanted to get to my sidebar. So, then we're going to create a new project. So, is there, like, a� a preferred way? Is there a Vite starter?

LENZ WEBERTRONIC: I would set up a blank Vite. I know people love boilerplates but I never see the appeal in them. You want to use three different technologies, each one has a boilerplate. How do you merge them together? It just usually doesn't work.

JASON LENGSTORF: Okay. So, we're going to set up a new Vite project and we're going to call this "Apollo Client React Suspense." And, React?

LENZ WEBERTRONIC: Yep. React. And we can throw TypeScript in, if it asks for that.

JASON LENGSTORF: Sure, why not. We'll go in here and we'll NPMinstall.

LENZ WEBERTRONIC: We need the two packages, Apollo/client and GraphQL.

JASON LENGSTORF: Okay. This has gotten easier. Again, it's been a few years since I've worked on this but I remember it used to be, when you used Apollo, it was four or five packages had to be installed.

LENZ WEBERTRONIC: Yeah. Apollo Client is modular. It was distributed in all these packages which had its drawbacks and its benefits. There's also good things that could be said about that. Right now, we have one, big package and it makes it a lot easier.

JASON LENGSTORF: The switch to ESM and you import the one piece that you need, it's so much nicer, for me as a dev, to not have to remember which thing came from which package. I know that here's your big box of tools and I pull out the tools I need and that doesn't cost me in my final bundle size.

LENZ WEBERTRONIC: Yeah, it will bite you in some instances. If you're an Angular user, you cannot import, so you have to import from Apollo Client Core and stuff like that. And I'd love to find ways around that to make that easier. But it's� it's a neverending fight.

JASON LENGSTORF: Got it. Yeah. No, I� [Laughter]. This is the� the [Indiscernible] task of being a software developer is everybody keeps moving our dang cheese. [Laughter]. All right. So, I've got my project here and� oh, wait. Let me actually open this project. So, I'm going to open up� we had GitHub. This one. This one. Here we are. Okay. So, here's our actual project. And I'm going to do a little "get init" so it's not faded out on us. Okay. Now I'm happy. Real straightforward. I have now installed Apollo Client and GraphQL and I'm ready to rock.

LENZ WEBERTRONIC: Yeah. That's all we need for now. So, we could jump into our appropriation TSX. Because we still have it in your clipboard, you can paste in the query so we keep it around for a while.

JASON LENGSTORF: Oh, right. Yeah. Whoops. I do still have that in my clipboard. Good memory. I would have immediately gone back and tried to just copy it again.

LENZ WEBERTRONIC: Okay. So, what we need to do is, we need to import a few things from the Apollo Client package.


LENZ WEBERTRONIC: We need� yeah. We need the Apollo Client, which is, like, Apollo Client, is one thing. We need a memory cache.


LENZ WEBERTRONIC: And, we need HTTP link. Importing also Apollo Provider because we're in a React world.


LENZ WEBERTRONIC: Okay. So, general advice, if you do serverside rendering, look up whatever your framework recommends you to do because we create a global variable within an Apollo Client instance. It would be shared between all the requests coming in and you never want to mix that up so there are ways around that. Since this is a clientside project, we can say [Indiscernible]. That needs an object as an argument. One of them is cache, which is memory cache.

JASON LENGSTORF: Any config for that?

LENZ WEBERTRONIC: The other thing would be, link, which would be a new HTTP link. And that gets the URI to a GraphQL endpoint, as an argument.

JASON LENGSTORF: Okay. And is that going to be this one, here?

LENZ WEBERTRONIC: Not exactly this one. I have a paste been� yeah. That one would�


LENZ WEBERTRONIC: That would have been it. Yeah.


LENZ WEBERTRONIC: By the way for everybody watching this later on YouTube, this endpoint will be down by the time you're watching it. I'm not going to keep this up. This is a mutable API. I don't want people uploading whatever they can.

JASON LENGSTORF: True. Yeah, that's fair. That's fair.

LENZ WEBERTRONIC: I'm sorry. So, we have a client. So, we wrap our application in a provider with that client, as an argument.


LENZ WEBERTRONIC: And then we could create a list component.

JASON LENGSTORF: All right. So, I'm going to create...

LENZ WEBERTRONIC: I just read in the comments, someone's curious if you're going to see React server components here? No, you are not going to see server React components. That's a whole other can of worms.

JASON LENGSTORF: Somebody was also asking if we were going to do the API side of things and we're not going to build a GraphQL API today. So, um, that, however, could be a fun followup episode. So, if you want to see that, drop a comment or send me a tweet or something, because I'm always looking for things y'all want to learn. Just let me know.

LENZ WEBERTRONIC: Yep. Okay. So, um, we need one more� yeah. Return something first. We need one more import and that's GQL, from the same Apollo Client package. And that's a string tag function so we can just� you can turn that comment, up there, into a constant essentially. So you could say [Indiscernible].

JASON LENGSTORF: Is there a convention for this? Do you do them all caps?

LENZ WEBERTRONIC: I personally don't have a preference, but most people on the internet do it with all caps.

JASON LENGSTORF: "GET ALL FILMS QUERY." You do the Screaming Snake case.

LENZ WEBERTRONIC: I'm always trying to picture screaming snakes. [Laughter].

JASON LENGSTORF: Okay. Quick tangent. I like this case so much that I illustrated it. Here. This is my Screaming Snake case. [Laughter].

LENZ WEBERTRONIC: Do you sell that as a TShirt?

JASON LENGSTORF: No, I don't sell any of these as TShirts. This was how I kept myself from going completely off the rails in the pandemic. [Laughter].

LENZ WEBERTRONIC: Come on, TShirts, like, fun hats. [Laughter]. I want� I want an umbrella with the unicorn soon. [Laughter]. It's going to be amazing. [Laughter].

JASON LENGSTORF: Oh, good. Good, good, good. All right. So, now I have my� so, this, a tag template literal, this is a function that will execute on all of the� these are very cool. We won't go into how they work, but look up "tag template literals." Is it just called a template tags?

LENZ WEBERTRONIC: I call them template tags.

JASON LENGSTORF: If you search for that, you'll see how they work. They're very cool and very powerful and a cool, little trick to add to your utility belt as a dev.

It reads nice as a function call. And now we can go ahead, in that component that you created, and we can just say, "constant result equals use client."

JASON LENGSTORF: "Good all films query."

LENZ WEBERTRONIC: Then we need a second argument, in this case, because this one has a variable.

JASON LENGSTORF: Oh, right, because we set it to the be the first� does it� variables.

LENZ WEBERTRONIC: Variables, yeah.

JASON LENGSTORF: First...and, we said� we'll just do 50. Okay. And then to start, I can just dump this, right?


JASON LENGSTORF: Okay. And, let's� can probably get rid of all of this and we'll just put our list in. Okay. Then we don't need that anymore. And I can start this appropriation. "NPM run dev." That will put us in 5173...and I broke something...

LENZ WEBERTRONIC: I think you closed it instead of minimizing. Ah, no� this is� this result� contains a reference to the Apollo Client instance and the reference is the client.


LENZ WEBERTRONIC: Destructure some things here and take a look at what's available there is, loading, for example. And there is data.

JASON LENGSTORF: Data. Yeah, all right. We can do something like, "if loading, return loading and otherwise, will stringify that data." And then, there we go. We're loading. Let me clear this and reload. Post� why did it� coooooooors!

LENZ WEBERTRONIC: Oh, no. [Laughter]. Um, let  let me give you an alternative URL to use. [Laughter]. Please use this one instead. See chat.

JASON LENGSTORF: Okay. This one.

LENZ WEBERTRONIC: With an "HTTPS," my error.

JASON LENGSTORF: Protocol error. What did I do wrong?

LENZ WEBERTRONIC: I'd love to know. Can you� oh, "/GraphQL."

JASON LENGSTORF: "/GraphQL," got it.

LENZ WEBERTRONIC: I wasn't prepared to use this one but I'm glad I have it.

JASON LENGSTORF: Protocol error. What are you mad about?

LENZ WEBERTRONIC: Can you open that in the browser?

JASON LENGSTORF: I sure can...did I typo?

LENZ WEBERTRONIC: I don't know, but that's the endpoint we've been talking to the whole time. It also works for me, on my machine.

JASON LENGSTORF: Oh, no. The worst problem to have. [Laughter]. Chat, did I typo this?


JASON LENGSTORF: Okay. Now, the good thing, here, is that we can� we can pivot. We can make it work. Do I have a VPN? I do not have a VPN�

LENZ WEBERTRONIC: This is amazing. [Laughter].

JASON LENGSTORF: Do I have a GraphQL API? Let's see...

LENZ WEBERTRONIC: Chat says they can hit it.

JASON LENGSTORF: Y'all can hit it? What is happening?

LENZ WEBERTRONIC: Did you do "HTTP," and not "HTTPS."

JASON LENGSTORF: Okay. Why would you� why would you choose now? Like, of all the times to be terrible?


JASON LENGSTORF: Let's see. All right. �

LENZ WEBERTRONIC: This is hilarious.

JASON LENGSTORF: There's some open GraphQL APIs. We can find some of these and we'll play with one of them instead of this one. SpaceX API. Fine.

LENZ WEBERTRONIC: In the meantime, let me see, real quick, if I can't just open Cores really quick. This is wonderful. This is so, so typical. But I also didn't think about Course because of course� ah, yeah, yeah, yeah, yeah, yeah. I think I should have this running very fast.

JASON LENGSTORF: Great. So just in the meantime, I'm going to swap this out, real quick, to show that it is, here's� here's the query coming in and actually, while you fix that, I'm going to get rid of some of this CSS because that's�

LENZ WEBERTRONIC: I've set it to allow any origin. This needs, like, a minute or two now to trickle through all levels of cloud. But then we should be able to� to use this.
In the meantime, uh, in the meantime, we could just set up the GraphQL [Indiscernible] because that takes two minutes and then we have TypeScript types.

JASON LENGSTORF: Yeah, let's do it. So I will undo� get back to this one, right?

LENZ WEBERTRONIC: Yeah. That one should work in about two minutes.

JASON LENGSTORF: In two minutes, that one will start works. Hey, look at it go!

LENZ WEBERTRONIC: Yeah. [Laughter]. Live debugging. [Laughter].

JASON LENGSTORF: This show wouldn't be what it is if you didn't have at least one mini disaster per episode.


JASON LENGSTORF: And so, we've livedebugged Course. The next thing is to get the code gen?

LENZ WEBERTRONIC: Yeah. Right now, everything is unknown and that's not very helpful. The next thing would be to create a code YAML. Nobody remembers how to set that up.

JASON LENGSTORF: Just in the route? And it's called "codegen.yaml." We don't have to go linebyline. In general, what we're doing here, we're pointing to our GraphQL API and we're saying, go through�

LENZ WEBERTRONIC: It will look for GraphQL queries in all of our TSX files and will generate multiple files. This is, like, one way of doing it. There are, like, ten million ways to set it up and this is the one I like the most. This will create type stuff TSX. Then it uses the operation preset which means, if you have a TSX file and you write a piece of GraphQL in there, it will create another file next to that, which is, like, your generate file name, which creates the type for that specific operation that you just wrote.
And the nice thing about that is the result is TSX. If you generate everything into one, big file, you have that one file and most [Indiscernible] on a preparation level. But they treeshake on a profile level so if that file is referenced, the first application will download all the queries there are and that can be a lot.

JASON LENGSTORF: That makes sense. All right. I'm with you. I've saved this. I understand what it does. How do I use it?

LENZ WEBERTRONIC: You call NPX GraphQL Code Gen. It's one word.

JASON LENGSTORF: This is me not doublechecking my work. [Laughter]. What that did is it should have generated a Types� am I looking at it? Where would it be?

LENZ WEBERTRONIC: Why did it immediately finish?

JASON LENGSTORF: I'm in the right folder. Yeah, Code Gen's right there. And I spelled this correctly?


JASON LENGSTORF: It's like it's not picking that up. Do I need to tell it to use this?

LENZ WEBERTRONIC: "Codegen.yaml." Right? Is it GraphQL Code Generator as the package name? Installation? It's @GraphQLminus/CLI because everything else would be too easy.

JASON LENGSTORF: Of course. Okay. How dare you. Could not determine executable to run? Did I�

LENZ WEBERTRONIC: Okay. A little bit further down, it says you can also do NPX GraphQL, minus code, minus generator. So, I'm confused. [Laughter].


LENZ WEBERTRONIC: Up on the top is the docs link.

JASON LENGSTORF: Up on the top, docs link. Introduction.


JASON LENGSTORF: Installation.

LENZ WEBERTRONIC: For me, it worked without installing it, but that might also be the error because maybe the query� you can also try that one, yeah.

JASON LENGSTORF: All right. Let's try this.

LENZ WEBERTRONIC: But without the image, probably.

JASON LENGSTORF: Without the image?

LENZ WEBERTRONIC: The image would create a conflict file, which we already have.
Yeah, this installs more. That makes sense to me.

JASON LENGSTORF: Okay. So now did it "module not found." Cannot found module GraphQL. Don't you lie to me. It's there.

LENZ WEBERTRONIC: Okay. I think we do what they say and install the whole thing. [Laughter].

JASON LENGSTORF: All right. All right. All right. Let's do it. So, we'll get this one, here.


JASON LENGSTORF: I think we already had TypeScript so I'm not going to install that again.

LENZ WEBERTRONIC: We should have, yeah.

JASON LENGSTORF: And then, don't need the Watcher. And we don't need the installation wizard. So, it would just be Generate is GraphQL Code Gen.

LENZ WEBERTRONIC: Probably had it installed, but hadn't tested this.

JASON LENGSTORF: Unable to find preset.

LENZ WEBERTRONIC: Okay. We also need to install that preset. Um...

JASON LENGSTORF: Install one of the following packages. This one?

LENZ WEBERTRONIC: The first one or the second one. I should have tried this on a completely empty project. [Laughter].

JASON LENGSTORF: It's all good. It's all good.

LENZ WEBERTRONIC: It's under� yeah.

JASON LENGSTORF: Near operation file preset. Open up for me. Come on, internet! It's trying its little heart out. So I'm going to grab this one...

LENZ WEBERTRONIC: Yeah, one of the things you set up once in your life and you completely forget about them because they just keep working until they don't and then you're frustrated again. All right. Now we have it.

JASON LENGSTORF: Ehhhh! We've got the types going here. And that means if I go back into this piece� I'm going to NPM RUN DEV and then I come back to my data.

LENZ WEBERTRONIC: The thing is, you need to import something and, you could import types, here, and everything, but that's a bit annoying. You can import the� just replace that "get vary" with document. This is not Screaming Snake case anymore.

JASON LENGSTORF: Sorry, replace it with what now?

LENZ WEBERTRONIC: It should autocomplete for you. Just replace this part.

JASON LENGSTORF: "Get all films" document. Okay.

LENZ WEBERTRONIC: We still need this because if you deleted the [Indiscernible] it won't be able to pick it up next time it runs. This one can be tree shaken out now.
But, if you have hover over data now�

JASON LENGSTORF: It is typed. And so� so that then means if I go in here and do a data dot and I've got my All Film list and I know what my entries look like and I can do, like, an add zero and go in here�

LENZ WEBERTRONIC: Entries is a function. Like, you are chunked into an area right now, I think.


LENZ WEBERTRONIC: It's an array. So, you're one step ahead with entries.

JASON LENGSTORF: And then if I can� there we go. We're autocompleting our way to victory, which is my favorite way to TypeScript. [Laughter]. Now what I can do is, we can set up some really kind of quick loop here, um, so I'll set up a unordered list and inside of my unordered list, we'll do, like, a and this will be the film. So, we can return...we'll give it a key so that React doesn't yell at me. And I guess, we'll just put the title in and hope that that's unique. Then we can put in the title. So, data� no. "Film.title." Oh, boy. Oh, God. And then we'd want the "film.rating." And then we would want to know the description. And, if I get rid of this extra stuff, over here...we have valid React and if I can get rid of this, because that was just me playing and then we come back out and we should theoretically have...there it is. Our list of� I'll zoom this in a little bit so people can see. But you get the title, the rating and then a description.

LENZ WEBERTRONIC: I hope that none of these films really exist. [Laughter]. On the other hand, the episode of the database administrator, I kind of want to see that one. [Laughter].

JASON LENGSTORF: Database administrator. [Laughter].



LENZ WEBERTRONIC: What we can do now is, take a look at the Apollo Client that we have, in the Apollo Client Dev Tools, which would be a browser extension that we still need to download. That's the one thing I didn't tell you ahead of time. [Laughter].

JASON LENGSTORF: All good. I can do that. Not my extensions�

You have to keep them in the Chrome Web Store. Gets me every time.

JASON LENGSTORF: Apollo Client Dev Tools. Here they are. Add them. And, then back out, here. Do I need to reload� nope, here it is. Okay. So�

LENZ WEBERTRONIC: Yeah. And there, you see [Indiscernible]. You can click into cache data on the right. You can see right now, it's not normalized, which is something that we can change now and it only needs one very small change. You need to request an ID.

JASON LENGSTORF: Right. Okay. So, let me get up into here. I'm going to request an ID. And then, because I haven't set up�

LENZ WEBERTRONIC: I need the [Indiscernible] yeah. That's true.

JASON LENGSTORF: And now that I've got this...

LENZ WEBERTRONIC: You can jump back into the browser and...yeah.

JASON LENGSTORF: And this one key, that means it's normalized?

LENZ WEBERTRONIC: If you click into one now, you'll see that now there are references in there. At least I hope so. Or, you click on cache� maybe results represents queries. On the topleft of the dev tools, there's� yeah, cache.

JASON LENGSTORF: Ah. And here's all our references.


JASON LENGSTORF: Got it. Very cool. So, later, if we start changing any of these, it knows by its ID and by its type, how to swap things in and out.

LENZ WEBERTRONIC: If we do a mutation and change the title of one entry and we get that one entry back from the mutation, for example, it would immediately update the list without needing to do another request to the list.

JASON LENGSTORF: All right. Let's� let's do that. We'll create one called "update." And what's the easiest way to do this? Should we just make a little field� let's see. So I would need to update, using their ID, so we can do� we can do it the hard way and I can manually copy the ID and we can edit the ID and the title and just send a mutation that way.

LENZ WEBERTRONIC: We can create a form now. We can create a button that does one GraphQL query because looking at the time, I think we have, like, 30 more minutes.

JASON LENGSTORF: Yeah, we have probably closer to 20, in reality.

LENZ WEBERTRONIC: Then maybe this is, like, not the rabbit hole to go down right now.

JASON LENGSTORF: Okay. Let's� how do we� how do we� I guess, let's see what we can do with actually getting the Suspense plugged in and then if we have extra time, we'll start playing.

LENZ WEBERTRONIC: Yeah. So, um, to get the Suspense stuff in here, you would essentially replace "use query" with "use Suspense query."

JASON LENGSTORF: Oh, and it's not loading anymore.

LENZ WEBERTRONIC: It's not loading it anymore because Suspense query guarantees it's always there. You can drop all of these question marks here. Or, at least the first one. I think the second one is nullable in the schema that we had here.

JASON LENGSTORF: Yeah, because I could get back "no films." Okay. So, we always have data.

LENZ WEBERTRONIC: So we always have data, if this renders. We want to wrap that list that we have there, in a Suspense component. So, you just do React.Suspense or Suspense that you import from React.

JASON LENGSTORF: Let's see. It doesn't� I don't think I...we will add the import. And, wrap it around. Okay.

LENZ WEBERTRONIC: Now we can give that a fallback property. And that can just be, for example, a string loading for now.



JASON LENGSTORF: Okay. So, functionally, it doesn't change the UX that we had before but from a development standpoint, this is kind of nice because I get to think about this as a completed query. I don't have to do all the management of all the different pieces and then this is the sort of management of what happens if I don't have the data yet.

LENZ WEBERTRONIC: Yes. This moves the loading state completely out of your component. A loading state is something you don't have to care about anymore. The loading state is something that you manage, at that point in the UI, where you want the loading state to be visible.

JASON LENGSTORF: And if I had, I don't know, four queries and four components, if they're all inside of the Suspense boundary, it's not going to� it's going to show me the fallback until all four components are completed?

LENZ WEBERTRONIC: Yes. You look at the whole UI experience, not the poof, poof, poof, poof, when everything renders in.

JASON LENGSTORF: I can make a decision, as a developer, if I have six things on the page, these four are thematically linked and create a separate Suspense boundary, outside of the first one, for the other two and say, these four have to come in together, these two have to come in together and maybe the two at the bottom are a slowerloading query and I know that so I want to make sure that that doesn't block the useful things up above. I like this because it changes the way I think about these things. I'm not thinking about a cascade of loading states. I'm thinking about, what are the cohesive units of my UI and being able to just kind of, you know, say, this is how the data works, right. This is what I'm going to do once I have it, but I don't have to worry about what to do when I don't have it. I can say, this is what happens when I don't have it, no matter how many components are in here.


JASON LENGSTORF: I really like that.

LENZ WEBERTRONIC: My colleague created� when he created this API, he created a full Spotify clone and that shows you where you highlight things and, like, superinteresting to see how you move around Suspense boundaries there. Maybe you have a Suspense boundary there where you playlists are, then you have another Suspense boundary around the player at the bottom because you want that to be one, cohesive thing that you see. And then you have another Suspense boundary over the content part of your page because you don't want the� the title of the playlist to come in and then, like, the first three songs of the playlist, you want all of that to show up at the same time and that way, you can create, like, these pieces of your UI that might pop in but you don't get, like, 2030 things coming in, one after another. But you get a very interesting, coherent UI.
And what we can do here is, also, that we� we can start with this list now and we could, uh� could add pagination, for example. We get this� this thing right now, if we create a variable to move forward, then you would pop back to the loader state with the current� current experience. And we can change that.
So, I� I'd say we� we add another variable to our query, which is...oh, gosh, you have to bring up that API Explorer. It's skip or after...

JASON LENGSTORF: Not this one.


JASON LENGSTORF: Not this one. This one. So, then we have our offset and the offset would be zero to start?

LENZ WEBERTRONIC: We would create a local state with zero and then we could crank that up when you start navigating.

JASON LENGSTORF: Okay. Got it. So, that will be our offset. Which will turn into a local state and then we'll use it� I'm just going to copy this...

LENZ WEBERTRONIC: But don't forget to read the ID.

JASON LENGSTORF: Read the ID. Good. So then we've got our offset, offset. Why are you angry?

LENZ WEBERTRONIC: You need to run the code gen.

JASON LENGSTORF: Oh, right. Need to run the code gen. Yeah, I think if I had a� if I was going to keep working on this, I would probably set it up to run in parallel with my dev it would be running the Watcher as well. But this is great.

LENZ WEBERTRONIC: One thing to highlight right now, from� from Dominic in the chat, the maintainer of React Query, with Suspense, you have to� especially be looking out that you can create waterfalls more easily if you use it look this. So, if you had, like, two components, like, had a child component to this one, that also should fetch data, it could only ever fetch data after this one finished rendering, so you want to do prefetching or moving things up to the top, all of that stuff, that� that's not a concern yet. That's something you have to look for in a real application. For a little application, it's going to be fine.

JASON LENGSTORF: What I'm going to do is set page to be� will set...what's our offset? Our� 50? So, we'll just do "current+=50." I guess we don't need to do the "+=."

LENZ WEBERTRONIC: Maybe do 10. We're going to scroll forever, otherwise.


LENZ WEBERTRONIC: If we do this right now, then you would get into that situation, where you always get the loading flickering in. So, we can try that.

JASON LENGSTORF: All right. So...we're loading. I've done something wrong. Or we're hanging? Come on, internet.

LENZ WEBERTRONIC: Everybody in chat, please stop [Indiscernible] my API. [Laughter].

JASON LENGSTORF: Let's see. You still pending? Um, let's see here... there we go. Okay. So, here's our� our first 10. Next page. Okay.

LENZ WEBERTRONIC: It skips back to the loading one and we want to prevent that because, like, it� this is bad on [Indiscernible].

JASON LENGSTORF: It's jarring.

LENZ WEBERTRONIC: In screen for a while before you get to the next one. We start using another React hook that's called "use transition." You can use that directly in this component.

JASON LENGSTORF: In the list component?

LENZ WEBERTRONIC: Yeah. Above the use state, probably. And this returns also two elements. The first one is a pending state, the second one is a transition function.

JASON LENGSTORF: Pending state start transition. Okay. Does that initialize with anything?

LENZ WEBERTRONIC: No, it doesn't initialize in any way. You can wrap that call to start page in transition and then another callback in there.




LENZ WEBERTRONIC: That transition hook is from React.

JASON LENGSTORF: Ah, yeah. This.

LENZ WEBERTRONIC: So, you can try it now.

JASON LENGSTORF: Okay. And...look at that. Much cleaner. Like, immediately cleaner.

LENZ WEBERTRONIC: But at the same time, this is a bit irritating for the user. We don't have a UI reaction at also what React does, in this point, is that in the background, it rerenders this component already with a new state and it tries to� so, in the background, it renders with page 10 and in the foreground, it keeps rendering with page zero but in the foreground, it changes the pending state from false to true so we can use that to maybe disable the button or gray out that. So, here, you could just� with a button� say, "disables equals pending state."

JASON LENGSTORF: Got it. And then when I come in here, it goes� yeah, you can see that it's thinking. Nice. And I could do something else, in here, too, like, I could say� I don't know. Like, we could say, uh...

LENZ WEBERTRONIC: Loading on there. Right.

JASON LENGSTORF: Right. And then that way, you're even more clear what's going on. Hey, yeah, we're doing stuff. Sit, please. Nice. Okay. I get it. Conehead Smoochy. [Laughter].

LENZ WEBERTRONIC: Yeah. [Laughter].

JASON LENGSTORF: Oh, my goodness.

LENZ WEBERTRONIC: Touching story of a womanizer and composer.

JASON LENGSTORF: Did you� is this just output from an LLM or something?

LENZ WEBERTRONIC: No, this is a dataset called Pagila, that's used for� I use it for loadtesting, if I need to fill up my memory, I use this database. [Laughter].

JASON LENGSTORF: So, so bizarre.

LENZ WEBERTRONIC: Yeah. But it works.

JASON LENGSTORF: So, this is great. This is great. We have� and this feels� you know, there are ways we could clean this up further. This feels good. We immediately communicate to the user when they click. We aren't jumping the UI around. We've got some consistency here. Is there anything else we can show in five minutes?

LENZ WEBERTRONIC: Five minutes is a tough call. The thing I would show is the documentation probably. In five minutes, we're not going to get anywhere, I believe.
So, if you look here, there's a point Suspense and that showcases this. There is not only the Use Suspense Hook that we have seen so far, there is a pair of hooks that exists, um, that are� yeah, changing variables. That's essentially what we did. It probably shows transitions next. Yeah, that's a transition.
And, this is essentially where we are. This could also give back partial data if you want.

JASON LENGSTORF: Interesting. Okay.

LENZ WEBERTRONIC: TypeScript will adjust for that, which is an important note. You can add boundaries. Error handling is also not a component concern any more. It is a parent concern now, which is important. If you get into the case of waterfalls� because Dominic already said that. You have a parent component, an HI component both request data. One thing you can do is fragment composition, if you have that set up. The other thing is that you can have the parent component already start the fetch. Maybe have a Suspense boundary in between and then in the client component, actually when the data is used, suspends that child part because Suspense components can also be nested inside of each other.
So for that, you use the "use background query hook" you see onscreen here, to make that request. That gives you a query wrap, which essentially a reference object. Like, you can't do anything with it, except pass it around as props. And in a child component later, you can call "use read query," will Suspense if the data hasn't been fetched yet and give you access to that data so that way, you can start prefetching in a parent component, much higher up.
It's already loading everything, but you� you don't need to completely suspend at the point where you start that fetch.

JASON LENGSTORF: And this is great, too, because if we look at how this would happen in the waterfall� and this is what you and Dominic work talking about� we have the appropriation. The appropriation has a Suspense boundary around the dog and the dog has to load the dog query and there's a Suspense boundary around that, as well and then inside this, we're showing the breeds, which has a Suspense boundary, that will run its own query around getting breed data so if we didn't have this background query, we would be� we would wait for the dog to load and once the dog loaded, we would wait for the breeds to load and so it would have a poppop, which is the whole thing we were trying to avoid.
By running it in parallel, this one and this one start at roughly the same time because they'll, you know, this and this will both start going at the same time, then we don't have to wait for this complete to then start the query. This is really clever stuff. As you get into more complex UIs, this is what bites a lot of us in the butt, is not having a clear understanding where we data gets called. This is a great way to sort of work around that, by understanding all of the queries that are going to be within the component tree and just sort them all right at the top. This is brilliant.

LENZ WEBERTRONIC: You explained it wonderfully, which I could have not done.
There is a loadable query and that's fetching in reaction to user reaction. You have a link, you want to preload something that might be used soon. Like, maybe you would use lazy query in the old paradigm and in a new paradigm, you use loadable query. It also gives you a query ref and then again, you use that with use query, immediately or at any later point inside a completely different Suspense boundary potentially.

JASON LENGSTORF: And so in this example, if I'm understanding correctly, you would say, I have a drop down, you can choose an item from the dropdown, instead of waiting for me to submit, when I changed the dropdown, we can start immediately loading the thing I'm going to get so in the case that I still needed to submit, it would be like a preload or if we were to do something where if I hovered or a product and I wanted to load reviews for that product, I could say, if you show intent to click on this thing, I'm going to start preloading stuff. Okay. This is very cool.

LENZ WEBERTRONIC: Like a good example would be a tool tip. You show the tool tip after 500 milliseconds of hovering, but you can already start fetching the first millisecond when the mouse is over the link. You start fetching. You start loading it. And you use it a little bit later and because of Suspense, then, it doesn't have the whole loading flickering thing. It's either already there or holds a current UI for a short moment in the current state.

JASON LENGSTORF: This is great. I mean, this is� this is very powerful stuff and I can see how, like, just how complex this can get in a production appropriation. And how having these sorts of things, that are, you know, here with the way that you've done it in Apollo Client� I know that Dominic is doing a lot of interesting stuff with [Indiscernible] Query. These libraries, like, if you only have one query on your page, sure, maybe it's overkill to reach for something like this. But as soon as you get into anything complex at all� this example, here, you have a list of things and each of those things, when you get inside of it, has subthings. That happens in just about every appropriation. So, very, very quickly you start hitting a point where having something like this is a worthwhile investment to get a good experience and to have good cache management. We didn't get a chance to look into the cache management of what happens once you start editing things but that's a whole other very, very cool thing that's worth checking out.
Lenz, I wish we had more time. [Laughter]. Where should people go if they want to learn more about this? We've got the docs up. Is there anywhere else that you recommend?

LENZ WEBERTRONIC: Yeah, there is another conference talk, Git Nation, Suspense. Search terms. Look for�


LENZ WEBERTRONIC: Yeah. Here, they use the Spotify application to show you how the user experience changes when you start moving around Suspense boundaries and the thing is, in your application, you probably really need to actually think about three or four loading states, in total, and those are probably intertwined with your layout and everything after that is components asking for data but the loading is happening, actually� the loading is happening completely differently in your appropriation. They showcase it so well. High recommendation, watch this talk.

JASON LENGSTORF: Great. All right. Well, I� I have lots of things to think about and lots of ways I want to start incorporating these data flows in. I can just feel it getting janky because I've been rolling my own data management so I can see potential for, even on something small, this is going to make a difference for me.
Let me send another round of folks to your Twitter follow. Make sure you go and follow Lenz there.
Another shoutout to the React docs, if you want to learn more details.
Huge thanks to our sponsors, Nx, Netlify. Vets Who Code has decided to end. They have made it possible for us to have live captioning today. So, we've had Vanessa, from White Coat Captioning, all day, taking these words down. Thank you so much, Vanessa. You can find those in the StreamText player. But, while you're on the site, make sure you go and look at the schedule because we've got so much good stuff coming up. We added a lastminute episode for next week. We're going to cover the big, old Astro release. I'm excited. Fred's going to come on. We're going to learn about how� another way to deal with, like, promise issues, async await with Charles. I'm going to do my best to keep up. We're going to learn about [Indiscernible], state in stateless applications, which I'm really excited about. It's going to be a good time on Learn With Jason. So, please, mark your calendars, you can subscribe to the channel, share this video, do all the things you would do to let people know you're here and having a good time.
With that being said, Lenz, thank you so much for spending some time with us today. Do you have any parting thoughts for the chat?

LENZ WEBERTRONIC: Thank you for having me. This has been a lot of fun. I think we covered a lot of ground. So, watch the talk, if you have time. Play around with this stuff. It's amazing. It's very different from the React we have known before. But it's really fun.

JASON LENGSTORF: Yeah. This is� it is very exciting to see how much things have progressed and with that, thank you all very much for hanging out. Lenz, thank you so much for giving us your time. We will see you all next time.


Closed captioning and more are made possible by our sponsors: