Nelson Michael Nelson Michael is a frontend developer from Nigeria. When he's not meddling with CSS, he spends his time writing, sharing what he knows, and playing games.

Using reactive variables with Apollo Client

5 min read 1473 107

Using Reactive Variables Apollo Client

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:

What are reactive variables?

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.

Creating a reactive variable

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.

Using reactive variables to read local data

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.

Using field policies and local-only fields to read local data

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.


More great articles from LogRocket:


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);

Using reactive variables to modify local data

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' }

Reacting to reactive variable data changes with 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.

Conclusion

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.

Get setup with LogRocket's modern React error tracking in minutes:

  1. Visit https://logrocket.com/signup/ to get an app ID.
  2. Install LogRocket via NPM or script tag. LogRocket.init() must be called client-side, not server-side.
  3. $ 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>
  4. (Optional) Install plugins for deeper integrations with your stack:
    • Redux middleware
    • ngrx middleware
    • Vuex plugin
Get started now
Nelson Michael Nelson Michael is a frontend developer from Nigeria. When he's not meddling with CSS, he spends his time writing, sharing what he knows, and playing games.

One Reply to “Using reactive variables with Apollo Client”

  1. 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

Leave a Reply