Skip to content

State Management with Apollo Client and Vue using Reactive Variable

This article was written over 18 months ago and may contain information that is out of date. Some content may be relevant but please refer to the relevant official documentation or available resources for the latest information.

State Management is an integral part of Software development with tools like VueX, Pinia which is like VueX 5, Redux, Context API, and others.

In our example, we will be using Vue3 composition API, a bit of TypeScript.

This article will assume that you already have a project setup with Apollo.

State Managemnet

Before we dive into what state management is and what it offers, lets understand few thing which are integral to it.

What is State?

State is a part of an application, such as user details, usernames, login information, and website themes(dark or light).

In simple terms, state is like a warehouse that's contents you can access when you need to from wherever you are.

What is State Management?

State Management is just simply a design pattern to help synchronize the state of the application throughout all of the components in the application. This also prevents us from passing too many props accross the application.

When to implement State Management:

  • When the application contains large number of components.
  • To prevent redundant data, knowing well some other components might need that data.
  • Prevent passing props across the application, making it messy.

For more explainations, you can check the links below:

How to implement State management?

There are so many ways to do it. But in this discussion, we will be implementing it with Vue Apollo.

Apollo Client

It is the client for Vue Apollo. It helps to easily integrate GraphQL queries and mutation in your application which, in our case, is Vue.

Reactive Variables

This is a new feature from Apollo Client 3.

Reactive variables are a useful mechanism for representing local state outside of the Apollo Client cache.

How to create a Reactive variable in Apollo?

This is quite simple since Apollo client provides us with makeVar.


import { makeVar } from '@apollo/client';

const counts = makeVar(0);
console.log(counts());
// Output: 0

/* Update the value of counts */
counts(1);
console.log(counts());
// Output: 1

const cartItemsVar = makeVar([]);
console.log(cartItemsVar());
// Output: []

/* Update the value of cartItemsVar */
cartItemsVar(['Vue', 'Apollo', 'State Management']);
console.log(cartItemsVar());
// Output: ['Vue', 'Apollo', 'State Management']

const isLoggedIn = makeVar(false);
console.log(isLoggedIn());
//  Output: false

/* Update the value of isLoggedIn */
isLoggedIn(true);
console.log(isLoggedIn());
// Output: true

What the above code means is we make use of makeVar to create a variable of any type be it boolean, number, array, or object. Also, by calling the variable that makeVar is assigned to without passing a parameter will only output its current value, but passing a parameter will update its value.

You can learn more about makeVar here.

Setup of the Project

We will be creating a state for a counter that does increment, decrement, or reset. But first, let's set up our enviroment.

Setting up the Reactive variable

Lets create our reactive variable in ./variables/counts.js:


import { makeVar } from '@apollo/client';

export const counts = makeVar(0);

Configuring the cache

Lets also update our cache config to something like this:


// Need to import the variable we reated
import { counts } from '../variables/counts';

// Cache implementation
const cache = new InMemoryCache({
  typePolicies: {
    Query: {
      fields: {
        count: { //The name we will be querying
          read() {
            return counts(); //Returns the updated value of counts
          },
        },
      },
    },
  },
});

Creating a component

Let's create ./components/Counter.vue component:


<template>
  <div>
    <div class="col-3">
      <h6>
        Count: <span v-if="!loading">{{ count }}</span>
      </h6>
    </div>
    <div class="col-3">
      <button @click="increment">Increment</button>
    </div>
    <div class="col-3">
        <button @click="decrement">Decrement</button>
    </div> 
    <div class="col-3">
      <button @click="reset">Reset</button>
    </div>

  </div>
</template>

<script lang="ts">
import { computed, defineComponent } from 'vue';

export default defineComponent({
  name: 'NumberCounter',
});
</script>

<script lang="ts" setup>
import { counts } from 'src/variables/counts';
import { useQuery } from '@vue/apollo-composable';
import gql from 'graphql-tag';

// This is to fetch the count value using the query
const COUNTERS_QUERY = gql`
  query Counter {
    count @client
  }
`;

const { result, loading } = useQuery(COUNTERS_QUERY);

const count = computed(() => (result.value ? result.value.count : 0));

const increment = () => {
  let cnts = counts();
  cnts++;
  counts(cnts);
};

const decrement = () => {
  let cnts = counts();
  cnts--;
  counts(cnts);
};

const reset = () => {
  cnts= 0;
  counts(cnts);
};

</script>

Please note that you can always get the counts value even without the GraphQL query. All you need to do is call count() like the example about Reactive variables, and force a re-render using loading as a ref.

Like this:


 <template>
  <div>
    <div class="col-3">
      <h6>
        Count: <span v-if="!loading">{{ counts() }}</span>
      </h6>
    </div>
    <div class="col-3">
      <button @click="increment">Increment</button>
    </div>
    <div class="col-3">
        <button @click="decrement">Decrement</button>
    </div> 
    <div class="col-3">
      <button @click="reset">Reset</button>
    </div>

  </div>
</template>

<script lang="ts">
import { ref, defineComponent } from 'vue';

export default defineComponent({
  name: 'NumberCounter',
});
</script>

<script lang="ts" setup>
import { counts } from 'src/variables/counts';
// loading ref to help re-render when there is a change so as to get the latest value of counts.
const loading = ref(false);

const increment = () => {
  let cnts = counts();
  loading.value = true;
  cnts++;
  counts(cnts);
  loading.value = false;
};

const decrement = () => {
  let cnts = counts();
  loading.value = true;
  cnts--;
  counts(cnts);
  loading.value = false;
};

const reset = () => {
  cnts = 0;
  loading.value = true;
  counts(cnts);
  loading.value = false;
};

</script>

loading ref to help re-render when there is a change so as to get the latest value of counts.

The manner you will prefer depends on what you want to achieve. But I will go with the example with the query as it still preserves the GraphQL feel.

Conclusion

State Management with Apollo Client saves you the stress of installing VueX, or Redux (for the React users), as long as the application makes use of Apollo. In this quick training, we learned about state and why state management is important to building and maintaining applications.

Further, we learned how to manage state by using a reactive variable in Apollo. If you need any help understanding how to use this training, or additional clarification, please feel free to reach out to me.

This Dot is a consultancy dedicated to guiding companies through their modernization and digital transformation journeys. Specializing in replatforming, modernizing, and launching new initiatives, we stand out by taking true ownership of your engineering projects.

We love helping teams with projects that have missed their deadlines or helping keep your strategic digital initiatives on course. Check out our case studies and our clients that trust us with their engineering.

You might also like

3 VueJS Component Libraries Perfect for Beginners cover image

3 VueJS Component Libraries Perfect for Beginners

For developers checking out VueJS for the first time, the initial steps are overwhelming, particularly when setting up projects from square one. But don’t worry! The VueJS ecosystem offers a plethora of remarkable component libraries, easing this early obstacle. These three libraries are pre-built toolkits, providing beginners with the means to kickstart their VueJS projects effortlessly. Let’s take a look! Quasar Quasar is among the most popular open-source component libraries for Vue.js, offering a comprehensive set of ready-to-use UI components and tools for building responsive web applications and websites. Designed with performance, flexibility, and ease of use in mind, Quasar provides developers with a wide range of customizable components, such as buttons, forms, dialogs, and layouts, along with built-in support for themes, internationalization, and accessibility. With its extensive documentation, active community support, and seamless integration with Vue CLI and Vuex, Quasar empowers developers to rapidly prototype and develop high-quality Vue.js applications for various platforms, including desktop, mobile, and PWA (Progressive Web Apps). PrimeVue PrimeVue is a popular Vue.js component library offering a wide range of customizable UI components designed for modern web applications. Developed by PrimeTek, it follows Material Design guidelines, ensuring responsiveness and accessibility across devices. With features like theming, internationalization, and advanced functionalities such as lazy loading and drag-and-drop, PrimeVue provides developers with the tools to create elegant and high-performing Vue.js applications efficiently. Supported by clear documentation, demos, and an active community, PrimeVue is an excellent choice for developers seeking to streamline their development process and deliver polished user experiences. Vuetify Vuetify is a powerful Vue.js component library that empowers developers to create elegant and responsive user interfaces with ease. Built according to Google's Material Design guidelines, Vuetify offers a vast collection of customizable UI components, ranging from buttons and cards to navigation bars and data tables. Its comprehensive set of features includes themes, typography, layout grids, and advanced components like dialogues and sliders, enabling developers to quickly build modern web applications that look and feel polished. With extensive documentation, active community support, and ongoing development, Vuetify remains a top choice for Vue.js developers seeking to streamline their workflow and deliver visually stunning user experiences. For newcomers venturing into Vue.js, the initial setup might seem daunting. Thankfully, Vue.js offers a variety of component libraries to simplify this process. Quasar, PrimeVue, and Vuetify are standout options, each providing pre-built tools to kickstart projects smoothly. Whether you prefer Quasar's extensive UI components, PrimeVue's Material Design-inspired features, or Vuetify's responsive interfaces, these libraries cater to diverse preferences and project requirements. With their clear documentation and active communities, these libraries empower developers to start Vue.js projects confidently and efficiently, enabling Vue developers to create polished user experiences....

I Broke My Hand So You Don't Have To (First-Hand Accessibility Insights) cover image

I Broke My Hand So You Don't Have To (First-Hand Accessibility Insights)

We take accessibility quite seriously here at This Dot because we know it's important. Still, throughout my career, I've seen many projects where accessibility was brushed aside for reasons like "our users don't really use keyboard shortcuts" or "we need to ship fast; we can add accessibility later." The truth is, that "later" often means "never." And it turns out, anyone could break their hand, like I did. I broke my dominant hand and spent four weeks in a cast, effectively rendering it useless and forcing me to work left-handed. I must thus apologize for the misleading title; this post should more accurately be dubbed "second-hand" accessibility insights. The Perspective of a Developer Firstly, it's not the end of the world. I adapted quickly to my temporary disability, which was, for the most part, a minor inconvenience. I had to type with one hand, obviously slower than my usual pace, but isn't a significant part of a software engineer's work focused on thinking? Here's what I did and learned: - I moved my mouse to the left and started using it with my left hand. I adapted quickly, but the experience wasn't as smooth as using my right hand. I could perform most tasks, but I needed to be more careful and precise. - Many actions require holding a key while pressing a mouse button (e.g., visiting links from the IDE), which is hard to do with one hand. - This led me to explore trackpad options. Apart from the Apple Magic Trackpad, choices were limited. As a Windows user (I know, sorry), that wasn't an option for me. I settled for a cheap trackpad from Amazon. A lot of tasks became easier; however, the trackpad eventually malfunctioned, sending me back to the mouse. - I don't know a lot of IDE shortcuts. I realized how much I've been relying on a mouse for my work, subconsciously refusing to learn new keyboard shortcuts (I'll be returning my senior engineer license shortly). So I learned a few new ones, which is good, I guess. - Some keyboard shortcuts are hard to press with one hand. If you find yourself in a similar situation, you may need to remap some of them. - Copilot became my best friend, saving me from a lot of slow typing, although I did have to correct and rewrite many of its suggestions. The Perspective of a User As a developer, I was able to get by and figure things out to be able to work effectively. As a user, however, I got to experience the other side of the coin and really feel the accessibility (or lack thereof) on the web. Here are a few insights I gained: - A lot of websites apparently _tried_ to implement keyboard navigation, but failed miserably. For example, a big e-commerce website I tried to use to shop for the aforementioned trackpad seemed to work fine with keyboard navigation at first, but once I focused on the search field, I found myself unable to tab out from it. When you make the effort to implement keyboard navigation, please make sure it works properly and it doesn't get broken with new changes. I wholeheartedly recommend having e2e tests (e.g. with Playwright) that verify the keyboard navigation works as expected. - A few websites and web apps I tried to use were completely unusable with the keyboard and were designed to be used with a mouse only. - Some sites had elaborate keyboard navigation, with custom keyboard shortcuts for different functionality. That took some time to figure out, and I reckon it's not as intuitive as the designers thought it would be. Once a user learns the shortcuts, however, it could make their life easier, I suppose. - A lot of interactive elements are much smaller than they should be, making it hard to accurately click on them with your weaker hand. Designers, I beg you, please make your buttons bigger. I once worked on an application that had a "gloves mode" for environments where the operators would be using gloves, and I feel like maybe the size we went with for the "gloves mode" should be the standard everywhere, especially as screens get bigger and bigger. - Misclicking is easy, especially using your weaker hand. Be it a mouse click or just hitting an Enter key on accident. Kudos to all the developers who thought about this and implemented a confirmation dialog or other safety measures to prevent users from accidentally deleting or posting something. I've however encountered a few apps that didn't have any of these, and those made me a bit anxious, to be honest. If this is something you haven't thought about when developing an app, please start doing so, you might save someone a lot of trouble. Some Second-Hand Insights I was only a little bit impaired by being temporarily one-handed and it was honestly a big pain. In this post, I've focused on my anecdotal experience as a developer and a user, covering mostly keyboard navigation and mouse usage. I can only imagine how frustrating it must be for visually impaired users, or users with other disabilities, to use the web. I must confess I haven't always been treating accessibility as a priority, but I've certainly learned my lesson. I will try to make sure all the apps I work on are accessible and inclusive, and I will try to test not only the keyboard navigation, ARIA attributes, and other accessibility features, but also the overall experience of using the app with a screen reader. I hope this post will at least plant a little seed in your head that makes you think about what it feels like to be disabled and what would the experience of a disabled person be like using the app you're working on. Conclusion: The Humbling Realities of Accessibility The past few weeks have been an eye-opening journey for me into the world of accessibility, exposing its importance not just in theory but in palpable, daily experiences. My short-term impairment allowed me to peek into a life where simple tasks aren't so simple, and convenient shortcuts are a maze of complications. It has been a humbling experience, but also an illuminating one. As developers and designers, we often get caught in the rush to innovate and to ship, leaving behind essential elements that make technology inclusive and humane. While my temporary disability was an inconvenience, it's permanent for many others. A broken hand made me realize how broken our approach towards accessibility often is. The key takeaway here isn't just a list of accessibility tips; it's an earnest appeal to empathize with your end-users. "Designing for all" is not a checkbox to tick off before a product launch; it's an ongoing commitment to the understanding that everyone interacts with technology differently. When being empathetic and sincerely thinking about accessibility, you never know whose life you could be making easier. After all, disability isn't a special condition; it's a part of the human condition. And if you still think "Our users don't really use keyboard shortcuts" or "We can add accessibility later," remember that you're not just failing a compliance checklist, you're failing real people....

Mocking API on Storybook using MSW cover image

Mocking API on Storybook using MSW

In this blog, you will learn how to mock APIs on Storybook using MSW. This blog will assume you have your project setup with either GraphQL, or a REST API like Axios or Fetch API and also will assume you have Storybook installed in your project. We will be covering how to mock for both GraphQL and REST API. In this project, we will use Vue and our UI tool. But don't worry. The sample code will work for whichever framework you choose. What is MSW? MSW(Mock Service Worker) is an API mocking library that uses Service Worker API to intercept actual requests. Why Mock? Mocking helps us avoid making an actual HTTP request by using a mock server and a service worker. This, in turn, prevents any form of break in case something goes wrong with the server you would have sent a request to. What is a Mock Server? A mock server is simply a fake server that works as a real server to help users test and check APIs . It imitates a real API server by returning the mock API responses to the API requests. You can ream more here. What is a Service Worker? A Service worker enable communication between the application, the browser, and the networks (if netwrok is available). They are intended, among other things, to enable the creation of effective offline experiences, intercept network requests, and take appropriate action based on whether the network is available or not. You can learn more about Service Worker API here. Use Cases Enough of all the stories 😃. Now we will be looking at two use cases: - GraphQL - REST API We will need to install some pulig ins to maximize what msw has to offer by running one of these commands in the root directory of the project: Installing MSW and the addon ` Generate a service worker for MSW in your public folder. ` Replace the placeholder with the relative path to your server's public directory. For example, the Vue command will be: ` You can check here to see what path your framework will use. Note: If you already use MSW in your project, you have likely done this before, so you can skip this step. Configuring Storybook In your .storybook/preview.js file, add this: ` You also want to ensure that your GraphQL set up is initialized in this .storybook/preview.js file if you are using Apollo Client. Creating our mock API Lets create where our mocking will be happening by first creating mock folder in the src folder. Create a data.ts file in the mock folder, and add this code, which will serve as our fake response. ` Create a mockedPost.ts file and add this code. ` Create a mockedUserProfile.ts file and add this code. ` The concept of interception comes into place with these mocked files. For example, if there is any request outside of the mocked request, msw won't mock it. So every API url or query we want to mock must correspond to the component that's data you are trying to mock, regardless of if the API url is authentic or not. Create a handlers.ts file and add this code. Handlers allow us to have multiple request, no matter its method [POST, GET]... ` How do we make use of the Handler? I created two components to test for our two use cases - Card - Posts Card component - Create a Card folder in your component folder. - Create a Card.vue and add this snippet ` - create an index.ts and add this code ` - create Card.stories.ts and add this code ` below is the UI expectation Posts component - Create a Posts folder in your component folder. - Create a Posts.vue and add this snippet ` - create an index.ts and add this code ` - create Posts.stories.ts and add this code ` below is the UI expectation Code Explanation We created a card and posts component that is making use of certain query/API call to get data. msw has a property handlers which accepts an array of requests, giving us the ability to add as many requests as we want provided that they are in the component. Overview Of the UI Below is an overview of the UI, which brings together the components: Whewww!!! 😌 Why mock? - You want test without hitting the actual API - Yhe API isn't yet avaible from the backend team. - During development to reduce dependencies between teams. - To accelerate third parties API integration. - during functional and integration testing. - to test various advanced scenarios more easily. - for demonstration purposes. Conclusion If you have any issues, we provided a repo which you can use as a template if you want to start a new project with the setup and use it to practice. Please let me know if you have any issues or questions, and also contributions are welcome....

The simplicity of deploying an MCP server on Vercel cover image

The simplicity of deploying an MCP server on Vercel

The current Model Context Protocol (MCP) spec is shifting developers toward lightweight, stateless servers that serve as tool providers for LLM agents. These MCP servers communicate over HTTP, with OAuth handled clientside. Vercel’s infrastructure makes it easy to iterate quickly and ship agentic AI tools without overhead. Example of Lightweight MCP Server Design At This Dot Labs, we built an MCP server that leverages the DocuSign Navigator API. The tools, like `get_agreements`, make a request to the DocuSign API to fetch data and then respond in an LLM-friendly way. ` Before the MCP can request anything, it needs to guide the client on how to kick off OAuth. This involves providing some MCP spec metadata API endpoints that include necessary information about where to obtain authorization tokens and what resources it can access. By understanding these details, the client can seamlessly initiate the OAuth process, ensuring secure and efficient data access. The Oauth flow begins when the user's LLM client makes a request without a valid auth token. In this case they’ll get a 401 response from our server with a WWW-Authenticate header, and then the client will leverage the metadata we exposed to discover the authorization server. Next, the OAuth flow kicks off directly with Docusign as directed by the metadata. Once the client has the token, it passes it in the Authorization header for tool requests to the API. ` This minimal set of API routes enables me to fetch Docusign Navigator data using natural language in my agent chat interface. Deployment Options I deployed this MCP server two different ways: as a Fastify backend and then by Vercel functions. Seeing how simple my Fastify MCP server was, and not really having a plan for deployment yet, I was eager to rewrite it for Vercel. The case for Vercel: * My own familiarity with Next.js API deployment * Fit for architecture * The extremely simple deployment process * Deploy previews (the eternal Vercel customer conversion feature, IMO) Previews of unfamiliar territory Did you know that the MCP spec doesn’t “just work” for use as ChatGPT tooling? Neither did I, and I had to experiment to prove out requirements that I was unfamiliar with. Part of moving fast for me was just deploying Vercel previews right out of the CLI so I could test my API as a Connector in ChatGPT. This was a great workflow for me, and invaluable for the team in code review. Stuff I’m Not Worried About Vercel’s mcp-handler package made setup effortless by abstracting away some of the complexity of implementing the MCP server. It gives you a drop-in way to define tools, setup https-streaming, and handle Oauth. By building on Vercel’s ecosystem, I can focus entirely on shipping my product without worrying about deployment, scaling, or server management. Everything just works. ` A Brief Case for MCP on Next.js Building an API without Next.js on Vercel is straightforward. Though, I’d be happy deploying this as a Next.js app, with the frontend features serving as the documentation, or the tools being a part of your website's agentic capabilities. Overall, this lowers the barrier to building any MCP you want for yourself, and I think that’s cool. Conclusion I'll avoid quoting Vercel documentation in this post. AI tooling is a critical component of this natural language UI, and we just want to ship. I declare Vercel is excellent for stateless MCP servers served over http....

Let's innovate together!

We're ready to be your trusted technical partners in your digital innovation journey.

Whether it's modernization or custom software solutions, our team of experts can guide you through best practices and how to build scalable, performant software that lasts.

Prefer email? hi@thisdot.co