Within a client-side app, can the creation & maintainence of global state be automated away without loosing capabilities?
Is there a easy-to-use, automated way to handle read-only server data on the client-side without building global state? I created a simple application in both Vue3 & React to investigated this. Using Apollo Client to connect with the same GraphQL API in both apps, the ability to do fine-grain cache querying in React presents a significant advantage. For now Vue@3 still requires a client-side global store to achieve the same functionality.
A client’s project is built with Vue@2, Vuex, Apollo Client & GraphQL. Coming from a React background, I thought this stack would enable the automated handling of server state. During a recent discussion I queried why Apollo Client caching was not being used in this way, instead of using Vuex to store all server data. The response was that it was not possible. To sense check my thoughts around this I created a simple application in both Vue3 & React to compare capabilities.
Technical Context:
The client/server architecture of SPAs1 neccessitates all server data be transmitted to the client. Tools like Vuex or Redux are then used to cache this data as global state, to reduce the latency penalty this pattern incures. This has several benefits: after the client buffer is primed it creates a perceived UI performance improvement, it removes the need for prop drilling, data can be accessed rather than copied, as well as acting as a communciation bus - potentially connecting separate aspects of an app.
Global state is the generic name for this client-side data store. The bucket that both a clients app state and all that server persisted data are dropped into. While the mentioned benefits are handy this approach also adds complexity, and an on-going maintenance overhead. Further more it handles these different data types, with their different characteristics, in the same way. This is extra work for a suboptimal solution.
Can this client data and server data be broken up for a better outcome achieved with less work?
Using Apollo Studio makes exploring the API simple, and just as easy to create GraphQL queries.
These queries were then copied across to the application, and wrapped with graphql-tag to enable GraphQL to parse those queries.
@vue/apollo-composable@4.beta is a Vue wrapper around @apollo/client@3.7.15. It provides a ‘hook’ style abstraction for making requests. Using this makes the whole data request lifecycle super, straight forward.
const { result, loading, error } = useQuery(queries.listFilms)
@graphql-codegen/cli to generate Typescript types from the defined GraphQL queries, and apply them to add type-safety.Firstly, recreate everything implemented in the Vue app. Then try to improve on several aspects:
readFragment method. As sections of the cached data can now be directly accessed this removes the need for prop drilling.
const production = client.readFragment({
id: `Film:${id}`,
fragment: fragments.filmProduction,
});
graphql-tag the codegen process generates its’ own template literal tag for parsing GraphQL queries. Switching this over achieves the same functionality while also automatic applying the types generated from the queries to the responses.
import { gql } from '../generated/gql';
const cacheConfig = {
typePolicies: {
Film: {
fields: {
releaseDate: {
read(releaseDate: string): string {
const date = new Date(releaseDate);
return `${date.getDate()} / ${date.getMonth() + 1} / ${date.getFullYear()}`;
}
},
FilmDetail query. This is enabled by passing the cached FilmProduction fragment across with the navigation, using the react-router-dom data APIs.
const film = {
...cache,
...data?.film,
}
extend type Film {
episodeIdNumeral: String
}
Time now to see how many of this enhancements can be ported to the Vue app…
@graphql-codegen/cli to use in place of graphql-tag, enabling the automatic application of type-safe on requests.npm create vite@latest.@graphql-codegen/cli enables automated type safety on request responses.@vue/apollo-composable wrapper package enables the simplified request handling and request deduping. However, the fine-grained cache querying is not yet available. There is no indication if or when that might become available. Back to Vuex/Pinia for now…Troubleshooting:
Learn More:
Single Page Application (SPA): Is a web application or website that interacts with the user by dynamically rewriting the current web page with new data from the web server, instead of the default method of a web browser loading entire new pages. The goal is faster transitions that make the website feel more like a native app. wikipedia ↩