State management is a critical aspect of building modern web applications. It involves the storage, retrieval, and modification of data that represents the state of the application. As applications grow in complexity, it’s even more important to have a straightforward, simplified approach for managing state in a centralized and consistent way.
This is where GraphQL’s Apollo Client comes in, providing a solution for state management in client-side applications. According to the docs, Apollo Client enables the management of local state alongside remotely fetched state, meaning we can interact with all of our application’s state with a single API.
In this article, we‘ll discuss how to manage local state using two features introduced in Apollo Client 3: reactive variables and field policies.
Jump ahead:
useReactiveVar
Reactive variables provide a flexible and powerful tool for managing local state within a JavaScript framework application. By utilizing reactive variables, we can read and modify local data anywhere within our application, without the need for a GraphQL operation. This allows for greater freedom and control over how we manage our application’s data and state.
It is important to note that reactive variables are distinct from the data stored within the Apollo Client cache. Since reactive variables are not required to follow a strict data structure, we can store virtually any type of data in them.
One of the key benefits of reactive variables is their automatic detection of changes using the useReactiveVar
hook. When the value of a reactive variable is updated, Apollo Client is able to detect that change and automatically trigger updates to any active queries that depend on that variable. This allows for seamless, real-time updates to our app’s UI, without the need for manual intervention.
Reactive variables provide a useful mechanism for managing local state in client-side applications and are an important aspect of Apollo Client’s state management capabilities.
Let’s dive into the syntax so that we can better understand how to create, read, modify, and react to reactive variables in Apollo Client.
Apollo Client provides us with a makeVar()
method that we can use to create a reactive variable. All we have to do is import it into our code:
// JavaScript import { makeVar } from '@apollo/client'; const name = makeVar("Mark Andrews");
N.B., for the examples used in this article, we’re using a sample React application
The makeVar
method takes a single argument, which is the initial value of the reactive variable. In this case, the initial value of the reactive variable is the string "Mark Andrews"
.
Once the reactive variable is created, it can be used in our application to read and modify its value.
To read the current value of a reactive variable, simply call the function that was returned by the makeVar
method without any arguments:
// JavaScript const name = makeVar("Mark Andrews") console.log(name()); // Output: Mark Andrews
After the reactive variable is created, the value of the name
variable can be accessed by invoking the variable as a function.
The value of a reactive variable can be read at any time, and it will always return the current value of the variable. In this case, the value of name
will be logged to the console as Mark Andrews
.
It is worth noting that reactive variables in Apollo Client are updated automatically, so even if the value of the name
variable is changed elsewhere in the code, the logged value will always reflect the latest value of the variable.
However, there is a way to modify a reactive variable in Apollo Client, as we’ll see a little later in this article.
We can also read data from a reactive variable by using the GraphQL useQuery
syntax the same way we would fetch remote data. The only difference is that we place the @client
directive after the field name to specify that Apollo must resolve the query on the client.
This works by using the cache type and field policies to define how a specific field in our Apollo Client cache is read and written to.
To better understand this, let’s look at an example:
import { InMemoryCache } from '@apollo/client'; import { name } from './filename'; export default new InMemoryCache({ typePolicies: { Query: { fields: { name: { read() { return name(); } } } } } })
In the above code, we’re exporting a new instance of the InMemoryCache
class with a custom typePolicies
object. The typePolicies
object is used to define how the cache should handle certain types of data returned by GraphQL queries. In this case, the Query
type is defined with a name
field.
We use the read
function to specify how the name
field should be read from the cache. In this case, it calls the imported name
function to retrieve the value.
Essentially, we’re defining a custom cache configuration for the Apollo Client to use when making GraphQL queries.
Now, let’s write a query for our name
reactive variable, like we would for remote data, using the useQuery
syntax:
import { gql } from "@apollo/client"; export const NAME_REACTIVE_VARIABLE = gql` query getNameReactiveVariable{ name @client } `
Our query, getNameReactiveVariable
, has only one field, name
, which is annotated with @client
. The @client
directive is used to indicate that this field should be resolved on the client side, rather than being sent to the server.
Now, we can use the query wherever we’d like in our application:
import { useQuery } from '@apollo/client'; import { NAME_REACTIVE_VARIABLE } from './filename'; const {loading, error, data} = useQuery(NAME_REACTIVE_VARIABLE);
To modify the current value of a reactive variable, simply call the function that was returned by the makeVar
method with a single argument which is the new value:
const name = makeVar("Mark Andrews"); console.log(name("John Doe")) // Output: John Doe
The value of the name
variable is updated by invoking the variable as a function and passing in the new value as an argument. In the above code, the value of the name
variable is changed from "``Mark Evans``"
to "John Doe"
.
It’s important to note that once the value of a reactive variable is updated, every active query with a field that depends on the changed variable will automatically update. This means that changing the name
variable will immediately impact other parts of the application that rely on the value of this variable.
It is also worth noting that we should not mutate an existing object or array, because in doing so, we may unintentionally affect other parts of the code that rely on that same object or array. This can lead to bugs that are difficult to track down. Instead, we should pass a new copy, like so:
const originalObject = makeVar({ key1: 'value1', key2: 'value2' }); let newObject = originalObject({ ...originalObject, key3: 'value3', key4: 'value4' }); console.log(newObject()); // Output:{ key1: 'value1', key2: 'value2', key3: 'value3', key4: 'value4' }
useReactiveVar
Reactive variables have the ability to cause changes in our application that are also reactive. Whenever we make a change to a reactive variable, any related queries will be refreshed and our application’s user interface will update accordingly. The useReactiveVar
hook allows React components to directly include the values of reactive variables in their state, without the need to wrap them in a query.
With the useReactiveVar
hook, we can access the value of a reactive variable in a manner that enables re-rendering of the React component whenever the variable is modified in the future:
import { makeVar, useReactiveVar } from "@apollo/client"; export const name = makeVar("Mark Andrews"); // we use the reactive variable in our component like so: export function Profile() { const username = useReactiveVar(name); }
Prior to the availability of the useReactiveVar
hook, we could only access the value of a reactive variable by using the useQuery
method.
Reactive variables and field policies are essential aspects of Apollo Client’s state management capabilities for managing local state in client-side, JavaScript framework applications.
In this article, we explored how to create reactive variables in GraphQL’s Apollo Client and use them to read and modify data and react to data changes.
Apollo Client reactive variables are an essential tool for any developer looking to build modern, data-driven web applications. With their powerful capabilities and flexible programming model, they provide a powerful solution for managing complex state on the client side, and are sure to play a central role in the future of web development.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowThe useReducer React Hook is a good alternative to tools like Redux, Recoil, or MobX.
Node.js v22.5.0 introduced a native SQLite module, which is is similar to what other JavaScript runtimes like Deno and Bun already have.
Understanding and supporting pinch, text, and browser zoom significantly enhances the user experience. Let’s explore a few ways to do so.
Playwright is a popular framework for automating and testing web applications across multiple browsers in JavaScript, Python, Java, and C#. […]
One Reply to "Using reactive variables with Apollo Client"
That’s a cool article, is possible to you share a real use case? That was my dificult to understand where this could be usefull in a real software