Dead Simple Apollo Client State

The Problem

As your React application grows, you will likely need a solution for state management. State management can be a difficult problem to solve, and although there are several solutions available (Redux, React Context, Apollo, etc.) some can be difficult to implement and each has its pros and cons.

Image by Arek Socha from Pixabay

The reasons I chose Apollo as a state management solution are

  • I love how simple it is to implement and use
  • I already use a GraphQL API
  • Local-only fields give me a great way to mix server and client state

Why Write This Now?

So Apollo client state isn’t new, but Apollo recently added an update that contains a new hook called useReactiveVar, this makes using Reactive Variables to manage client state significantly easier to implement and use.

It’s so simple you can implement the entire system in only a few lines of code!

Image by StartupStockPhotos from Pixabay

The Example Code

If you’re interested in seeing this live, you can check out the code sandbox below! The full example is available on GitHub as well if you want to run it locally.

Some Background

I’ve been using Apollo to manage client state for a little while now. I was really excited when Reactive Variables came out since it was so much easier than using the cache to store things that only exist on the client-side of the application.

Originally getting the information from the Reactive Variable in a way that triggered UI updates was a little bit of a pain. It involved a query, type policy, and you had to fetch it using Apollos use query hook which involved destructuring the information you want from the data object it returns.

Not a big deal but with the new useReactiveVar hook you can now get it with a single line of code.

What Is a Reactive Variable?

Reactive variables are a simple way to manage state in your application. To quote the Apollo docs…

New in Apollo Client 3, reactive variables are a useful mechanism for storing local state outside of the Apollo Client cache. Because they’re separate from the cache, reactive variables can store data of any type and structure, and you can interact with them anywhere in your application without using GraphQL syntax.

Most importantly, modifying a reactive variable triggers an update of every active query that depends on that variable, as well an update of the react state associated with any variable values returned from the useReactiveVar React hook. A query depends on a reactive variable if any of the query's requested fields defines a read function that reads the variable's value.

The Implementation

Okay enough about why we’re doing this, let’s actually implement this!

Image by Tumisu from Pixabay

The Cache

Since in our example, we’re only worried about client state, our cache is very simple and can be instantiated in a single line. For a new implementation, I usually store my cache and any Reactive Variables in a file called cache.js.

// cache.jsexport const cache = new InMemoryCache();

The Client

Next we need to create an Apollo client that we can pass into our Apollo Provider.

// app.jsconst client = new ApolloClient({ cache});

The ApolloProvider

Next, we need to wrap our app in an ApolloProvider, this gives the children access to all the Apollo hooks we’ll want to use in our app.

// app.js<ApolloProvider client={client}>
... the rest of our app
</ApolloProvider>

The Reactive Variable

The setup for these is so simple, all you have to do is instantiate them like this in a single line.

// cache.jsconst nameVar = makeVar("default");

What we pass into makeVar will be the default value for the Reactive Variable, if you don’t have a default value, don’t worry, it will work just fine with nothing passed in!

Why Is the Variable Called “nameVar” Instead of “name”?

So you might be wondering why the variable is called nameVar instead of name. I originally followed this pattern because it was how the examples were in the Apollo docs. At first, it didn’t make sense to me but if you imagine the following scenario.

// Getting our name
const name = useReactiveVar(nameVar);
// Setting our name
nameVar("Aaron");

If we named our var name, we wouldn’t be able to use name for our actual data, and setting it wouldn’t be clear.

By following the nameVar pattern, whenever we see an object name followed by Var we know we’re setting something in the client state which makes it much easier to follow what’s happening in the code.

Still Here?

Here’s what your cache.js and app.js files should look like now, pretty simple right?

cache.js
App.js

How Do We Use It?

Now we have our client state all set up, but how do we actually use it? Using this is so simple, it’s just a single line to read, and a single line to write.

Setting the Name Value

Setting the state with Reactive Variables is extremely easy, this was my primary reason for switching to them when they were first introduced.

Basically the Reactive Variable becomes whatever you pass in.

// Lets set the nameVar value to "Aaron"nameVar("Aaron");

Getting the Name Value

Getting the value is so simple now with the useReactiveVar hook, it can be done with a single line of code! Before this hook was available you needed to get your value using the use query hook, which required a type policy to work, and a query itself. This is why I love this new hook so much, it couldn’t be simpler!

// Can be ran from any child of ApolloProvider!const name = useReactiveVar(nameVar);

That’s It!

Pretty simple hey?

If you ignore imports, sets, and gets, that’s only a five-line setup, I don’t think client state could get any easier than this. Thank you Apollo for doing this, it makes for a lot less boilerplate and saves us developers a lot of time in the long run.

Don’t forget all the code is available from GitHub if you want to see the full example!

About the Author

My name is Aaron Watson and I’m a Full Stack Developer based out of St. Johns, Canada. If you’d like to get in touch, here is my Email, LinkedIn, GitHub, and website.

Thanks for taking the time to read this, I hope you found it useful. If you did please consider applauding, sharing or subscribing for more content. If you have any questions or comments don’t hesitate to reach out!

Image by Daniel Reche from Pixabay

--

--

--

I’m a Full Stack Developer from Canada specializing in React, React-Native, Flask, and Apollo.

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Best Practices for Logging in Node.js

A Guide To Prototype-Based Class Inheritance In JavaScript

Using ES Modules with Dynamic Imports to Implement Micro Frontends

A beginner guide to API fetch.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Aaron Watson

Aaron Watson

I’m a Full Stack Developer from Canada specializing in React, React-Native, Flask, and Apollo.

More from Medium

From OpenAPI to a working integration in minutes

Typescript Connect4

Printing in Node.js with Electron (ElectronForge + node-printer + webpack)

Payload CMS Version 0.15.0 brings publishing, versions, performance, more