Daniel Afonso === [00:00:00] Hi there, and welcome to PodRocket, a web development podcast brought to you by LogRocket. LogRocket helps software teams improve user experience with session replay, error tracking, and product analytics. Try it for free at logrocket. com today. My name is Paul, and joined with us is Daniel Alfonso. He's back with us again to cover his latest conference talk, You Don't Know Server State Yet. a developer advocate over at OLX, author of State Management with React Query. Welcome back, Daniel. Hi. Thank you for having me back. It's a pleasure to be here. It's a pleasure to have you. I mean, This recent talk that you had digs into some things that maybe we gloss over as developers because we don't need to reach so deep or. We don't want to so excited to get into talking about state not just on the client, but in the server before we get into this. Can you tell our listeners a little bit how you got into web development specifically or technology? Did you start out in technology? What brought you here? Yeah, sure. . I didn't initially started in the [00:01:00] in web development I started as a back end so I was a back end developer mostly focused on full stack but for around a year two years something like that but then when I met this thing called React I said, okay, no, it feels like this is something that I want to try out for the next couple of years. And yeah, so I did, I kept staying on the web development world until I met the other cool thing, which was developer advocacy. And I said, okay, now this is where I even want to take my career, but still keep the web aspect of it. So yeah, that's kind of been my very straightforward path in tech right now. So you must be very qualified then to tell us about How we don't know server state yet, because this is maybe naturally a back end centered topic. If you started out as a back end developer and you came into React and web development, were you looking at it from a thousand foot stick away and you were going, Oh my gosh, this looks messy. Like, how do you manage state? Or was [00:02:00] this a realization that set in over time as you started to use the different libraries and frameworks and you went, something doesn't feel right here. I think that's definitely like the main issue that I started having with state was there was so many tools to manage it so many things that we could use, like, and then there were the native solutions, like there were a lot of aspects to it. There were the normal recommendations of react. With the use states and the use reducer, and then the context to wrap everything up. And then on the other side was everyone like, Oh, we need to use Redux or we need to use just stand or recoil or MobX or whatsoever. And there were so many solutions. And I think like the issue for me started when. We had to implement in my team that I was working at that time, we had to say, okay, now we need to do deal with caching when we were fetching a lot of data, we're storing it in context, but now we need to deal with caching. This is an issue that we have right now. And we started implementing these things.[00:03:00] But by ourselves and there was a lot of confusion because first we were spending a lot of time implementing these things by scratch with a lot of time means, okay, now we're taking longer to deliver stuff to production to our users and yeah, more code to maintain. And this is what was when I started thinking, perhaps there was a simple way to do this. Perhaps there's something new and this is when coincidentally at the same time, I think it was. I might be wrong, 2020 or 2019 Tanner Linsley did a talk on react summit about server state and in there introduced this tool that he had built called react query. And one of the aspects that he mentioned a lot on this talk, and that stayed with me was we are looking at our state just as a global state. There's just this thing that's a container where we put everything. So we have our Redux, we have our context, we have our things, and we are just throwing everything in there. But there's different aspects to dealing with state. There's [00:04:00] even different types of state and each one of them has different challenges and ways to look at. There's different types of state. Your talk is called, we don't know server state. I can naturally guess there's client state, but what other types of what is state? What are we zeroing in on here? So that's a fun thing because state is usually defined like as this mutable data source that you can store data related to your application. And typically this data will define now your code renders. I like to open this talk with saying that state is the art of your application because. That's what it is. It's very tricky to build any apps without state. You probably could for a bit, just to prove me wrong, but then you'd say, yeah, it's not worth the effort. Like, let's just stay with state. And that's the thing with this type of state, there's different types of state. When usually we're treating state as this global container and. I like, one of the things that I would like to make, I like to make clear with this talk is, we need to split them. We need to split our states [00:05:00] in, our global state in at least two. Client and server state. Client state, there's like these different aspects of it. So it's a state that it's local uh, it's synchronous, so you don't need to wait to get it. And probably it disappears whenever you refresh your application. This is usually the definition for client state. A good aspect of it might be imagine that you have a team toggler and you don't persist it between sessions that this is a completely different topic, but every time every application, you have your team, it defaults in white mode, then you want to search for, dark mode. So , this is kind of one of the examples of what client state might be. But then we have server state, and this is where , I would like to say and quoting Star Wars, this is where the fun begins. Because this is the part where this state first. You don't own it. Your application doesn't own it. It exists somewhere in the database over the internet. And if it exists somewhere, it's probably even shared by other users using your same application. So there's no guarantees that it's up to date. So when you're accessing it or changing it, someone else might have accessed it and changed it. [00:06:00] And typically you need to wait for it. So you need. Do either do without the fetch request or something like that for you to um, to get this date. So this is kind of the definitions I like to give for people for, okay, this is client and this is server state, but client state has this specific challenges. I won't go into them right now, but server state. It's the funny part, because I already mentioned one of them, caching. Caching is probably like the main challenge when dealing with server state. We need to make sure we get our data, we can cache it if the data proceeds. For instance, in an SPA, one of the issues that happened a lot was... If our data was in for a specific component, if we're not um, sharing it into a context or a global store or whatever, every time I went to that component, that data fetch request would retrigger or we would lose that data. We wouldn't have it. So now we would add implement these mechanisms to deal with caching for this type of data in our SPAs. And then there's a bunch of, stuff. So managing if your data is outdated, so [00:07:00] mechanisms to know, okay, this data is... Considering that this server state is shared by all the other users using our application, probably someone else might change it. So we need to have a mechanism for the code to understand, okay, probably I need to do an automatic request to get our data just to make sure that my cache is up to date is considered fresh and not stale. And then there's a bunch of other challenges and patterns that we often see in dealing with server state, like, data prefetching, optimistic updates mutations, this is a standard one, but pagination, infinite queries. So I could name a bunch of them and probably stay here like for an entire week, just listening all these issues. And that's the thing, when you think about implementing all of these solutions by yourself. Imagine all the overhead that you're going to add into your application, because now you're, you're going to be the responsible for updating it, for fixing it, for deleting it. And at the same time, you're still expected to do your main job, which is ship something to [00:08:00] the user. And this is actually something that, well. Personally, me and my team didn't want to have. So I think that this is when this Tanner Winsley presented React Query, which is this solution to deal with server state. It just related with us and said, okay, this is our Holy grail right now. This is going to be the thing that is going to save us a bunch of time. And if it saves us time, it saves us money. I think that this is kind of the direct relation when you're dealing with product teams. And yeah, it ended up, like I said, saving us a bunch of time, money. And other things. So the name that you're telling us right here, it's react query. And that's inherently tied to react, but I feel like a lot of the issues that you're talking about here could easily be thrown into like any context. We're talking about like APIs, backends, like what's going on in my database. Do you feel like react query? Can be used for these other types of domains and where do you [00:09:00] think the most overlap between what we're talking about today within the context of like React back and state server state, excuse me Where does that overlap with like traditional API and back end development the most where we can draw parallels? So on the first part right now. It started as a react query, but now It is migrated to a superset of libraries called 10 stack query and this is a fun thing because I think it's changed on v4 of 10 stack query. Pretty much what they did was they created a superset which has the base implementation and then they create adapters for each framework. So there's react query. Whenever I say react query, I mean the react adapter of 10 stack query. So right now, every time you hear 10 stack query, it means the superset of libraries to deal with data fetching. Okay. And then you have adapters for, I know that there's for Solid, there's for Vue and there's for Svelte. I'm not sure if there is for Angular already, but pretty much you [00:10:00] can say React query, Solid query, Vue query, Svelte query, you're mentioning that specific framework adapter of 10 stack queries. So right now it has, they renamed it and I think it's a great decision because now you have this. Bring this amazing thing that was react query to other frameworks to help save time , in other places. So that's one of the changes. And if throughout this discussion that we're having, you hear me interchanging between 10 stack query and react query, it's because the change was like one year ago or something, but I'm still not used to, and usually I just use react query. So if you hear the name react query, don't worry. I'm talking about the react adapter of 10 stack query. So it sounds like this is pluggable into a bunch of different frameworks and maybe in the web application context But some of these issues as a back end developer yourself. I'm sure you must be familiar you come into caching problems with your query stack whether that be just a simple back end API That you're throwing together for your team, for another team of microservice. [00:11:00] Does TanStack query allow us to leverage any of these builds in non web application contexts? . So in this scenario, pretty much what happens is you have your backend API, your backend team. I would even say that they are separated from the full because usually what happens is they build your API. They have their own ways of implementing such a connection with the database. They might even have other different layers of caching with CDNs and whatsoever. But 10 stack query has its own. In browser caching, I would say that's the way to, to look at it and all these solutions and all these challenges and things to deal with all these things, like I mentioned previously, all the challenges it already has out of the box. So pretty much every time you call one of the hooks in this case for data fetching, which is called use query, you already have, a way that will give you solutions to deal with specific issues out of the box. So you don't have to implement any of them. And one of the fun things that, [00:12:00] that you have here, and this is, I like to say about is that react query and then stack query is protocol agnostic. So one super cool thing here is it doesn't matter if your backend team has built the rest API as a GraphQL API, heck you might even use soap. It doesn't matter because as long as you have. What's called the query function, a function that returns a promise, you can have whatever you want inside of it and react query doesn't care if it's GraphQL, if it's SOAP, if it's REST, and this is one of the super powerful things because you might even have two different types of set data source or that are APIs and At the same time, as a developer, as someone using the react query, you don't need to, well, if you are using GraphQL, there's going to be some nuances as well or so for whatever, but once you have this query function, you don't need to care about all the stuff behind art. You can have someone just. You'll wrap, wrap, and have something like get data source or whatever. This is just more [00:13:00] implementation aspects of it, but it's super interesting because it makes this flexibility that the library has that not many other tools have. So if you had to implement support for imagine, Oh, I want to cache data that comes from GraphQL or cache data that comes from, um, that comes from REST API or cache data that comes from SOAP, that would probably be. Extra adopters or stuff and having these things already out of the box implemented for you. It's just great because I was going to say, we have built in caching behavior that developers are very used to leveraging in a variety of frameworks with GraphQL these days. That's right out of the box, but You're stuck with GraphQL. You really have to mold your whole workflow around that. So, what your comment that you just offered right now really, I think, helps highlight one of these key differentials. It's protocol agnostic, right? Is it fair to say that? Awesome. Yeah, I like to say that um, I think that this is kind of the definition I give everyone. It's React queries protocol. Agnostic collection of hooks for data [00:14:00] fetching and managing your server state. That was like the most shortest, sweetest, beautiful wrap wrapped up version of that. That was great. You had the elevator pitch ready to go. Let's dig a little bit into some of the. Use case details like you just mentioned some of like the hooks that we can do before we hop into that. I just want to remind our listeners that this podcast is brought to you by LogRocket. LogRocket offers session replay, issue tracking, product analytics to help you quickly solve and surface impactful issues affecting your user experience. So with LogRocket, you can find and solve. The issue is faster, improved conversion, adoption of your application, and just spend more time building a good product, less time debugging in your console and stuff like that. So go over to logrocket. com today to check it out for free if you're interested. So, let's dig into some of the use case details. About this awesome data fetching solution that we're talking about here. The number one [00:15:00] hook that you brought up, useQuery. It's how we get data. We probably recognize it from GraphQL. What is useQuery at its core? Is it a fetcher? And how might you step into using it? So use query. And one thing that's important to mention is that the naming changes in two different adopters. So I think in React in view, it's called use query and in Solver and Svelte, it's called create query, but the way it works, it's the same, it's a hook that whenever you add it to a component, whenever a component renders by default, it will use what's called a query function that this it's this function that I mentioned that where you can wrap over your Protocols, a solution to fetch data and this query function waits for a promise. And when, whenever you get the data, the query function returns this data to the hook, and then the hook use something called the query key to cache the data internally. So this is kind of the gist of how use query works, the default behavior. So. I think the important things to know is query function. It's a [00:16:00] function that returns a promise that will you use to fetch your data. So this is pretty much where you put your if you're doing um, for that request, you can use Axios because GraphQL, where you put your data fetching client inside and fetch your request and fetch your data, sorry, returns it. And it uses this thing, which is called the query key. To identify this data on the cache and this is super powerful because by default, imagine that you have three components that rent at the same time, but the three components need the same data source. This is super interesting because here it's where React Query does what's called deduping of duplicated requests. So what happens, what would happen traditionally if you were using your own client and doing these things is these three clients would fetch the data and they would be three separate requests for fetching the data. React Query here identifies that. There's three data sources trying to get the same data. So it only sends one request and whenever you get this data, it populates all the other three sources. So [00:17:00] it's already, as you can see, besides caching, it already does like what's called the duping of duplicated requests out of the box, which is super powerful and. Yeah, it's pretty much a container as well for your data. So usually use query, it's what you use for fetch data. But yeah, it's super powerful. It's super customizable and then you can use it to do a bunch of patterns as well. So you can do parallel queries. So you can have dependent queries as well. So you can have queries that only execute one after the other. So there are a bunch of things that you can do with use query that will. Yeah, pretty much fix most of the data fetching scenarios that you have. And then the caching out of the box is just The cherry on top. Is it, is React query or tan stack tan query, right? In this example that you're laying out, able to identify the shape of the data and which data might be duplicated via the resolver. Or is this the query key that you're talking about? Well, pretty much [00:18:00] the query key is what identifies the data that you get. So if you have two hooks using the same query key, then if they're mounting at the same time, there's going to be this data fetching concurrency at the same time, there's going to be the looping and whatsoever, but imagine that you renders and you do a data fetch request. This data is stored under your query key and. After a couple of minutes, you have another component that will render and it will have the same query key. What will happen is React query knows, okay, oh, I already have this cached. So it will get this data already for you. And depending on one property that is called still time, it will decide if this data is still fresh. So we still assume that this data is not outdated or if data is stale. And if this data is stale, it will also trigger a new data fetch request. To repopulate the cache. So pretty much the key, the query key is what controls all the caching and this identification of what data should be there. And the fun thing is. [00:19:00] If the second component retriggers a request, fetches the data, and the first one is still rendering, the data will update there as well because they share the same query key. So therefore they share the same data on the, from the cache. So the query keys almost in, in essence, describe a tree of data dependency. Yes, I like to say that the query key should be treated as we treat dependency array on use effects or use MIMO. So, and this is interesting because there's other things at hand here. So you, I like to say that the query key should be as descriptive as possible as the data that we need for a query, because then it enables you to do another thing, which is your query key can be injected into a query function through something that is called the query function context. And why is. It's super interesting because then it allows you to build patterns like, for instance, pagination. Imagine that you have a query key that you have oh, by the way, query keys need to be arrays. If you used 10 stack query or react query prior [00:20:00] to v4, I think it was not mandatory, but now they made it mandatory. So just a disclaimer, they need to be arrays. And imagine that you have an array that on the first position you have A string calls called data, whatever, and then on a second parameter of the array, you have page, and then you have filters. If these things can be injected into the query function, it can be used to customize your data fetching requests. So this example that I just laid out, it's pretty much how you can build paginated APIs. So because you have a page, you have filters, and if this thing goes into the query function, which is the function that is responsible for doing data fetching, you can. Check them into the URL that you want to fetch the data for so this makes it even more powerful because you can have this like symbiosis between a query keys and query function. And one of the one other thing that's important to mention is if a query key changes, then you're not talking about the same data source. So there's going to be probably a new data fetching request. So imagine that You have a query [00:21:00] key with let's just use a normal example that you have. Okay. I want to fetch for data source A or from data source B. And if you have this variable in your query key, when you're injecting it into the query function to customize the route that you get, whenever you change, for instance, click on a button and it changes state for this value to be value B, the query key will say, okay, no, this is not the same thing. So it's not the same data that we need. Let's retrigger a new request to get this data. So the query keys are. Kind of like the thing that controls the entire full of your query, but also enables you to do caching. And then there's all these beautiful patterns that come afterwards with it. So the query keys seem to be deterministic in a lot of these examples, because you have to set it in order to take advantage of. Exactly. Yeah. So in use query the query key and query function are mandatory. So you always need to have them. It's the only two. Things that you need by default, they always have to be there. Without them, it won't. I haven't tried it yet. Probably TypeScript will yell at me or something like that. Probably, [00:22:00] yeah. It it doesn't work without them. Now, what about the second most used hook? I am gonna guess it's used mutation because it's like the other side of the coin here, but please correct me if I'm wrong. Okay, awesome. If we have data fetching on one side, which is the way we can get our data, we need some way that we can create, update, or delete our data. So this is where mutations come into the loop. Mutations are the things that we use to update, create, or delete our data from our data source. And then this hook, use mutation or create mutation, which is responsible. Or well, executing a mutation, the way it works is compared to use query. It doesn't execute automatically because it doesn't make sense. We want to be able to describe, okay, I want this mutation to either execute when they submit the form or when the user clicks on this button whatsoever. And the way it works is there's a mutation function where we can add. It's going to be either or get or delete or update or mutation as well. Whatever depends on what [00:23:00] protocol or whatever we were using. It's the same thing as the query function, but for mutations and the objective here is. To mutate data. And there's this you cause use mutation that receives the mutation function. And by default, it returns something that is called mutate. And this mutate function is expected to receive some parameters, which are the parameters that we then we're going to be used to execute or meet our mutation. So let's have a default behavior where we have our form state all focus on an app. And whenever we submit this form state is grabbed by. A function or by the event or whatsoever, and we get the data from the form. And what we do is we call mutate with this form, which is data, and then it will execute the mutation. And this look is super powerful as well, because then it allows you to do a bunch of cool patterns. And one thing that is. Like, one of the easiest ways of doing this, which is optimistic updates. I think that this is kind of the next, one of the next patterns you can [00:24:00] focus on. And that's usually a very huge pain to implement by yourself. But use mutation makes it super simple to do. Is these use, use mutation processes rooted in like form encoded data, you said? No. You can pass whatever. You can pass whatever you want. So you can have, you can even have state or whatever. It doesn't need to be forming coded. There's a, there's this function called mutate that can receive data from whatever, any part of your application. And when you call it, this data will be injected into your mutation function, and then you can use it to do whatever you want to create, update, delete, whatever. So that's pretty much the simple flow of it, of how it works. One of the things that I know people love about some of the newer frameworks and libraries that help maintain types is that you can do things like in Remix, you have actions, in Svelte you have, I think it might be actions as well in Svelte or something similar when you post your we call it the mutation, [00:25:00] it's typed, and your resolver has those types, what's the best way that you found to keep that same level of type system safety using Svelte? The use mutation. So, I think like one of the cool things is it kind of just, I might be going I'm not sure if I'm wrong here or I'm right. But I think like by default, one of the cool things is if you type your mutation function and whenever you pass it to the, to these mutation, it will just infer what that thing expects to receive. So it will keep this flow and this control of like, okay, whenever I need to call mutate, because my mutate. Mutation function expects to receive this. We typed it that way, then use mutation will know. And in this case, mutate will know that you expect it to pass it. So immediately TypeScript will start yelling at you when you say, Oh, you're trying to pass data that shouldn't be here or pass data that That you're missing a date or whatever. So I think that this is also one of, one of the cool things that that I've seen with it in production. That's super [00:26:00] cool because that brings type safety to a protocol agnostic environment. Yeah, that's huge. Yeah. I, and I think like they've been doing a great job dealing with TypeScript usually when I. Started with React Create, I wasn't that very into type safety, but like they started implementing a bunch of stuff and like, I think everything is pretty much rebuilt, just use TypeScript out of the box. So the entire library is built with TypeScript. So it has a lot of, adds a lot of power to development if you're using TypeScript as well. Yeah, the speed to be able to make a change later on and have the red squiggle pop up is just, it's unmatched. Daniel, could we hit one more on our triad right here of hooks? Use infinite query. What is an infinite query? What does that even mean? So there's a pattern when you're dealing with data fetching where imagine that you're seeing a screen and you're scrolling and as you're scrolling new data is showing up and this is usually what's called [00:27:00] an infinite query. You use infinite query. It's a. A wrapper over use query that allows you to deal with and implement if you need queries in a way that's much more simple than if you had to build everything by scratch by yourself, it has wrappers that allows you to have access to the previous page, the next page, but it just. It's super powerful. I haven't used it a lot because unfortunately I haven't had a lot of I forgot the word, a lot of situations in production development where I had to implement infinite queries. But the one time I had to, it was just a blast. It saved me a bunch of time. Previously, there was even a, another hook called use paginated query, but it was deprecated because now. Since you can do this pattern that I mentioned of injecting your query key into the the query function function directly by using the query function context, it doesn't make sense because React Query just takes care of that thing. But yeah, infinite queries, use infinite queries as a wrapper over the the use query hook that allows you to Have a better experience when you're dealing with [00:28:00] infinite APIs. Now, one of my last questions has to do with uh, your mentions about framework support here. So you mentioned Svelte, Solid, of course React. Does Remix play into the picture at all? So that's one of the fun things because when Remix or Next and people come into and talking about data that's fetched to SSR or SSG and people like, okay, but Then we don't need react query or this because usually with some react query on a client rendered application, because it just takes care of everything. But the fun thing is you can still use it because one of the things that happens a lot is okay, you server side rendered a bunch of stuff, but then most of the applications. I've seen this happen a lot, just default to client behavior after a bit. And of course, and this is where you need like all the things that react query already had. So you need caching, you need all these things that you already had. One of the things that you can use with remix next when you're doing, for instance, server side branding, there are two patterns. One is called initial data and the other one is [00:29:00] called the hydration boundary. So pretty much the initial data pattern, let's focus here on remix. You fetch your data in your loader and whenever you pass this water to the client to when it renders, you can inject the data that comes from the water into react query into a property called initial data and then react query knows, okay, by default for this specific query, this will be the initial data. So react query, whenever your code now comes into the client, react query knows, okay, these data was already fetched and is used to populate this specific query key. And then there's another pattern called hydration. Which other hydration boundary, which pretty much allows you to, whenever you return from your voter react query will dehydrate the the data. This can be interesting because you can do that, the prefetching and a bunch of other stuff. And you just have this instance of uh, your query client, which is. It's pretty much the heart of React Query. It's the thing that contains your query cache and all the other things. You dehydrate your query client. And when, now the browser is doing dehydration, React [00:30:00] Query will hydrate that query client and have it assume the data that was already fetched on the server. So, when you're doing, you can use the server side rendering aspect of, okay, now we can use it to populate and build our query client and our query cache and whatsoever. And when you come to the client and we, Default to the client behavior. Then we just let react query do its thing. This really reminds me of like within the front end context of passing and taking control of the DOM, depending whose strengths are in what part of the UI that you're running. So here, like, if you're going to push everything to just client side rendering, that's when you're saying. You could take a look at your situation again and maybe benefit from it. Gotcha. Okay. If you're just using servers, imagine that you only need the data for the initial load or for something that you're just displaying and you're not going to do a lot of data fetching throughout the application, then yeah, give react query a shot, because 10 stack query a shot, because it will, most of the time when you start dealing with data fetching on [00:31:00] the browser and all those things happening again, then it's going to be your number one ally in this case, I think it's. Like it's probably the number one library I install in all the things right now when I have to do any sort of data fetching or mutations or whatsoever. If I know I'm going to have a lot of browser and client side interactions happening. Well, Daniel, this has been enlightening, not only for I'm sure the people who have never heard of ReactQuery, but for people who have and like maybe want to try some interesting patterns with it. I love some of the patterns that we went over today. If people wanted to follow you. Daniel Moore, because you are DevRel, I'm sure you post things out and about. Where can people find? Yeah, so people can find me now. I think it's called X, not Twitter anymore. But Daniel J. Ciafons. I have the same name pretty much on LinkedIn and every other social network. So Daniel J. Ciafons, it's where you can. What can you can search to find it pretty much any social network [00:32:00] and if people want to get started with tan stack query would you recommend react as a good framework to get started with or is there okay i think it's but it's react query started in react so there's probably the one that's more Mature, I would say, even though now it's spreading to, to the other ones, but it's where it all started. So I would say React it's the, and it's probably the one that it's easier to find documentation, to find docs, to find written video content. So yeah, I would say React is probably the best way to start. But with 10 stack, but you can use other frameworks that the docs are very good. So a huge shout out to the team that's been doing all the work with 10 stack, because the docs are amazing. It's, they are one of the best documentations for dealing with stuff that I've seen. That's so great to hear. Cause I can really make or break a framework library. Yeah. That's awesome. So we got, we're cross framework, cross protocol. That's why I got to ask. So react has got to be [00:33:00] a good spot to start, right? Because stuff's out there. Well, Daniel, thank you again for your time, for coming on and for talking about server state and all the ways that we can tackle it. Thank you so much for having me. It was a pleasure to be here once again and yeah, thank you.