Client-Side GraphQL with React, v2

Setup Urql Provider & Caching

Scott Moss

Scott Moss

Superfilter AI
Client-Side GraphQL with React, v2

Check out a free preview of the full Client-Side GraphQL with React, v2 course

The "Setup Urql Provider & Caching" Lesson is part of the full, Client-Side GraphQL with React, v2 course featured in this preview video. Here's what you'd learn in this lesson:

Scott introduces the Urql library as a lightweight alternative to Apollo for client-side GraphQL. He walks through the process of setting up the urql client in a React app by creating a GQLProvider component that wraps the entire app and provides the client instance. The GQLProvider uses the Urql library to create a client with the necessary plugins and options, including the cache exchange and fetch options.


Transcript from the "Setup Urql Provider & Caching" Lesson

>> Scott Moss: Let's go to the part that we'll be using. So that's how you would do it. And plain old fetch, we're not gonna use fetch, we're gonna use something, we're gonna use a GraphQL Client. There's so many of them. The most popular one is called Apollo. They have a frontend component, they have a backend component.

On the server side GraphQL, I will be using Apollo on the server side. But for the frontend, I'm actually not using Apollo on the frontend and it's not because I don't like it. I don't think it's good. I actually think it's probably the best one you can use.

I just don't think it's the appropriate tool to introduce people to client-side GraphQL because, it's so complex and it makes so many assumptions about your knowledge of GraphQL. It gets quite confusing its I kind of think of it as the Angular of GraphQL, where it's useful and it's good.

But like, the terms they use and the things that they do are off putting for people when they first learn it's just so much. Whereas like this one, which is pronounced Er-kull or Urql but I'm pretty sure it's pronounced Er-kull, that's too clever for it not to be pronounced that way.

So I [LAUGH] I think that's what it's. I'm pretty sure that's how you print. At least that's what I call it. I call it Er-kull but I heard some people say Urql. This was like a more lightweight client. It has pretty much the same features as Apollo, but their APIs is a lot easier to digest and it's just simpler.

Their docs are not as intimidating. Apollo is such a huge company at this point. Their documentation is like looking at Google's documentation. If you ever had to look at Google's SDK documentation, it's just the most terrifying thing you've ever seen. Apollo's kind of like that. So it's not that it's bad, it's great, I love it, but not the best thing to use when you're starting to learn.

So we're gonna use Urql. What is a GraphQL client? What the hell is a GraphQL client? Well, it's basically a wrapper around the fetch like I showed you, but it does a bunch of stuff. It gives us hooks for React so we can do queries and mutations. If you ever used something like React Query or SWR with Next.js, it's like that.

But for GraphQL, that's the best way I can describe it, which is kinda confusing because you can also use GraphQL for those things as well. I know it's very confusing. The biggest difference I would say is something called normalized caching. We'll talk about that eventually. But because everything in GraphQL is essentially a node it can do normalize caching on the frontend.

Which allows you to do like optimistic updates and like better cache rewriting, whereas if you do something like React Query or SWR, you don't get normalized caching, you have to rewrite the cache on a request basis. Like for this whole request, rewrite this cache whereas maybe I don't wanna rewrite the whole request.

I just wanna change just this one to do in this list of to dos. So normalized caching is something that a lot of people speak highly of, but I would say most people don't even really need it. But anyway, we'll be using it, we get it for free.

So first thing first, let's set up this Urql client in our app. So what we need to do is need to go to our app folder and make a new file called gqlProvider.tsx and here is all the code for it. So if you want you can just throw it in there I'm gonna go through it all one by one just to kind of tell you like what's actually happening and I'll be referencing this so I keep my code very similar to what's here.

So let's go do that. So I'm gonna go back to my code. I'm gonna go to my app directory. I'm gonna make a new folder. I'm gonna call it gqlProvider.tsx. And again, this is I'm on the client zero branch. So if you're on the main branch, this is already here.

It's already filled out. If you're like, why? How's he making this file? It's already here. You're on the wrong branch. Go to client zero. It should not be there. If it is there, I don't know how it got there, but everything from the client should be deleted. So first thing is we're gonna import all of our stuff from Urql It should already be installed when you did an npm install earlier.

So, what is it? @urql that's how you know when an open source project made it, they get that at namespace, like they go from just urql and then like they get some donations and now it's @urql so let's see though they got some sponsors. Cool, so we got these few things.

I'm just gonna copy them. Gotta put them in here. Well, we'll talk about these in a minute when we start using them. We're also gonna get useMemo from Reacts which rip is basically dead, with new React 19, which I'm sure Brian's gonna teach a course on very soon.

And yeah, just to keep this, if you never use Next.js app router, this won't mean anything to you, but if you have what I'm doing. You have to put this directive at the top called use client. If you don't know if this means, this just means I just wanna stay in React land.

Don't give me any of the server side Next.js stuff. Just keep this vanilla client side React please. So that's what we're gonna do for this whole course. I don't want to get into next day a specific thing. So I'm gonna be doing use client pretty much in all my components just to make sure that what we're doing here can apply to any React app that you use.

But note gone forward, React 19 does support server components and all this stuff. It's not specific to Next.js. Next.js didn't invent server components. React did, so in the future, none of this is gonna matter. You're probably gonna do server stuff anyway, but just so we can just get rid of that barrier of all that.

I'm just gonna put use client everywhere. And then also, I just don't think it makes sense to do GraphQL on a server component in the same API that your app is hosted on. Because you can just talk to the database directly, you can just skip the network requests and just pull in your ORM.

So it doesn't really make sense, in my opinion, to do GraphQL on the server if you're using Next.js. So we're just gonna use use client that just makes more sense. So there we go this cache exchange. This is the normalised caching. And again, we'll talk more about that in a little bit.

But this right here, you get to get is like Redux is basically the Redux. It's like Redux. It's like automatic Redux for all your entities from your GraphQL queries it'll like figure out where they need to go and like store them in a Redux the way and and do updates that way.

That's basically what this is. I don't know why they may have to come up with terms like cache exchange and like, all this stuff. I don't know. These other inputs here and these are just utility functions that I created. You can go look at them, but basically this URL function right here just figures out the full path of the URL.

If you go to production, it'll be that. If not, I'm assuming you're on 3,000 and it's gonna be that. That's actually where the GraphQL API is. We'll load it up in a second you'll see what I'm talking about.
>> Scott Moss: And then this getToken one. We're using JSON Web Tokens for authentication, so this getToken function just gets the token from local storage.

That's all it does nothing fancy. I'm not using cookies. I tried to use cookies, and the way that I have API set up on server, it just wasn't working, and I didn't feel like doing the hack and explaining the hack. So we're using, we're just gonna store it in local storage.

But in production, you probably wanna store your JSON Web Tokens in a secure HTTP only cookie for sure. And just have it be sent every single time, assuming you're on the same domain. If you're not, then this point doesn't matter. Okay, so the goal here is to make a provider.

And then we're gonna make a client that we need to memoize and then we're going to wrap the children in that. So let's do that. So I'm gonna export default GQLProvider call it whatever you want, really. Actually, you know what? I don't know why I have it like that in notes cuz I actually write my functions like this.

I just like arrow functions way better. So I'm just gonna go to an arrow function here. And I like to just export default at the bottom.
>> Scott Moss: There we go, so we got that. I know this thing's gonna take its children because it's a provider, so there's gonna be children here, so I'm gonna take that.

And then from here, the strategy is we just want to keep the same client for the whole app. Because if we make a new client every single time, then we're gonna a new redux every single time. And then what's the point? So we want the whole app to experience the same cache.

If you were doing this server side, you definitely want a new client every request. Otherwise all your users would share the same cache and that would be a security risk. So you wanna create the client on the fly per request on the server side, which is another reason why I'm doing use client everywhere.

So I don't have to address that and talk about it because I think that's too specific to Next.js and I said that we will cover the Next.js course. So for this one, we're gonna use memo and we're gonna create this client. So let's do that. So we're gonna say const clients and then what do I have here?

Yeah, ssr equals useMemo if you don't know what useMemo is, it's basically a hook that memorizes a function to memorize something basically just means if I call this function again with the same arguments, give me the results that you compute it the first time and don't compute it again.

This is perfect for the client. That way, if I try to get the client, it'll just give me the client that it created the first time and won't create it again. So that's what memorization is. It's a hook, so we pass it dependency array of nothing because we just wanted to run on the initial render of this component and never again.

So we have that and then, what we wanna do is we have to create this SSR exchange. The best way I could describe this well, I guess I need to describe exchanges for a little bit and exchanges is a plugin. Why do they call it exchange? I don't know.

It's just a plugin. Apollo calls it a link, I think Urql calls it an exchange. It's literally just a plugin. This SSR plugin just makes sure that this doesn't break on server, essentially. And you might be thinking like, why is this gonna run on a server? I thought you put use client.

Next.js it's a little tricky. There's a difference between server components and server side rendering. Those are two different things by doing use client, I opt out of server components, but this component still does server side rendering. Still gets rendered on the server, its business logic won't execute in the context of a server like a server component would.

So it's not streamable it doesn't have a suspense built into it. So it's not a server component, but it will be rendered on the server. So if I just throw the word window in here it will 100% break. So I have to do type of window how to do things like that.

And this plugin, this ensures that the cache gets transferred over from server side rendering to client side rendering on hydration cuz that's actually what happens. If you don't know hydration is it's basically just an object that gets created on the server with all the data that you made and then it gets passed to the frontend so the frontend can pick it up.

It's just like an exchange of data over the network layer. This just makes sure that that runs smoothly. Yeah, that's what this is so we got that. And then we can actually create our clients. This one interesting so let's walk through this one. So let's say,
>> Scott Moss: Client equal and then we have the createClients function here.

This is gonna take an options object. There's a few things. We have the URL. So this is our input to our GraphQL API, which for us is gonna be 3,000/API/GraphQL. It's already there. And then we have our plugins, fancy exchanges here. And then we have options we wanna do on fetch.

So let's do that. So we have our URL. It's already in my scope, so I can just do that. And then we have our exchanges, aka plugins. We're gonna do the cache exchange, which is a function. I'm just gonna put an empty object in there for now, like that.

We're gonna pass in the SSR like that. But then we need to pass in the fetchExchange. fetchExchange is exactly what it sounds like. It's telling Uqrl to use fetch to make the API calls. You can have, like for instance, if you didn't wanna use fetch, you wanna use Axios or some other custom HTTP library that you created, you would make an exchange and use that instead, but anybody got time for that.

So we're gonna use fetch.
>> Scott Moss: Okay, and then lastly, it's gonna be fetchOptions. fetchOptions, this is gonna be a function and it returns an object of like options you wanna pass to the fetch. Literally anything you can pass to window.fetch, you can pretty much pass here. So what we wanna do, the strategy is like, we wanna send our JSON Web Token on every single request.

That way it's always there. You would do this with fetch anyway. So what we wanna do is like go look in local stores, get the token. If it's there add it to the authorization headers a getToken, if not, just return an empty object. So that's what we're gonna do here, just to make sure we can pass our token.

If you use cookies, you won't have to do this.
>> Scott Moss: So I'm gonna say getToken, and then I'm gonna return. If there is a token, then I'm gonna return an object with headers that has authorization. And it's gonna be bearer and then the token and then if there is no token was gonna put it in the object,
>> Scott Moss: Pretty straight forward, nothing crazy there.

And then we just need to return a tuple here with our client and our SSR since we're trying to destructure it. So I'm just gonna do that, return our client and ssr.
>> Scott Moss: Okay.
>> Scott Moss: So now that we have our client, we can go ahead and start creating this provider.

It's pretty simple, we're just gonna return the UrqlProvider. I really like that name Urql. I'm like where can I use that? Get a cat, another cat or a dog named Urql. That would be cool, UrqlProvider. We just need to pass it the client, pass it the SSR plugin, and then obviously, wrap the children.

So let's just do that really quick. So I'm gonna return that, get our UrqlProvider, and then clients is gonna be clients. And then SSR is gonna be SSR and then wrap our children. Otherwise, nothing's gonna show up on the page.
>> Scott Moss: And just like that, three easy steps, we have our UrqlProvider.

>> Scott Moss: So why do we need a provider? You don't need a provider to do window.fetch. So why do we need this? Well, it's just for caching. It's just for caching and for this logic that's literally it. It's like, if you might not know this, but there's a hook in React called useReducer.

It's like, why would you use this? UseReducer, it's like a local Redux for a component, but if you wanted this to work across your whole app, you would put this in a context so your whole app can share the same reducer. Otherwise, how would they know? How would they share?

So in order for us to share the cache, we have to create a provider, because react uses context, which is just like internal state. Context is basically like props that don't need to be passed down, any component can access the context, no matter what their parent is directly to it.

So if all the state is in the context, then any component in your app should be able to access this cache. Which means you should be able to use Urql queries anywhere in your app and access the same cache, which is the whole point. So that's why we need a provider.

Will it work without one? Absolutely they'll just all have no cache to share. So next thing we need to do is go to our providers.tsx and we need to include it, I'm sorry, we need to go to our layout.tsx on the root. There's a lot of layouts. Make sure you go to the one on the on the root of app should be /app layout.tsx not the one in I'm sorry.

This one, not the one in auth, almost messed up. Not the one in auth, not the one in dashboard, but this one. One on the route. It's a lot of layouts. It's the Next.js thing. It's layout everybody gets a layout now. So what we're gonna do is this provider's run here is for our component library.

I'm going to pass in our UrqlProvider inside of this one or what Did I call it? Is my core UrqlProvider? GQLProvider, okay. I'm gonna pass mine inside the providers, the component library. And the reason I'm doing that is just because I don't know what this component library does, what its context.

And I don't wanna wrap it inside of my context and mess it up somehow, like I don't know, maybe this component library does GraphQL stuff, maybe it uses Urql internally. And if I wrap it inside of my context, my UrqlProvider it could conflict with that. So I'm gonna put mine inside of the component library one I know for sure it doesn't, but that's just me being careful.

I've had things like that to pass and those are the hardest bots to track down because it won't break. It just won't behave the way you thought it would and you'd like what's going on? And it's like, the providers are weird because this thing uses something similar. So, always just try to get as close to the children as possible with my providers and keep third-party providers outside of my providers, it's like a priority provider thing.

Nobody really talks about that, but it's real.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now