From Vuex to Apollo:

GitLab journey

 

+

=

❤️

+

=

?

Natalia Tepluhina

Senior Frontend Engineer

Core Team Member

Google Dev Expert

@N_Tepluhina

+

@N_Tepluhina

@N_Tepluhina

 Vuex

export default () => ({
  isLoading: true,
  addedLines: null,
  removedLines: null,
  endpoint: '',
  basePath: '',
  commit: null,
  startVersion: null,
  diffFiles: [],
  mergeRequestDiffs: [],
  mergeRequestDiff: null,
  diffViewType: viewTypeFromQueryString || viewTypeFromCookie || defaultViewType,
  tree: [],
  treeEntries: {},
  showTreeList: true,
  currentDiffFileId: '',
  projectPath: '',
  commentForms: [],
  highlightedRow: null,
  renderTreeList: true,
  showWhitespace: true,
  fileFinderVisible: false,
  dismissEndpoint: '',
  showSuggestPopover: true,
});

@N_Tepluhina

@N_Tepluhina

Dispatch an action

Trigger

REST API call

Success?

Commit 'success' mutation

State changed

Commit

'error' mutation

Yes

No

@N_Tepluhina

@N_Tepluhina

@N_Tepluhina

Handling API responses

@N_Tepluhina

Send query

Success / error

State changed

Queries

@N_Tepluhina

Success / error

State changed

Mutations

Trigger

mutation

Update cache

@N_Tepluhina

Local state* = Apollo Cache

* - (everything is Apollo Cache)

@N_Tepluhina

const el = document.getElementById('js-design-management');
const { issueIid, projectPath } = el.dataset;

apolloProvider.clients.defaultClient.cache.writeData({
  data: {
    projectPath,
    issueIid,
  },
});

Setting initial local state

@N_Tepluhina

Query data from local cache like we query it from API

@N_Tepluhina

query projectFullPath {
  projectPath
  issueIid
}

"Normal" query...

@N_Tepluhina

query projectFullPath @client {
  projectPath
  issueIid
}

...vs "local" query

@N_Tepluhina

Vuex getters

export const getCurrentDesign = state => designId =>
  state.designs.find(design => design.id === designId);

@N_Tepluhina

Local query + resolver

query getDesign($id: String!) {
  design(id: $id) @client {
    ...DesignListItem
  }
}

@N_Tepluhina

Local query + resolver

Query: {
  design(ctx, { id }, { cache, client }) {
    return client
      .query({
      query: projectQuery,
    })
      .then(({ data }) => {
      const edge = data.project.issue.designs.designs.edges.find(
        ({ node }) => node.filename === id,
      );
      return edge.node;
    })
  },
},

@N_Tepluhina

Vuex action + mutation

export const toggleFileFinder = ({ commit }, visible) => {
  commit(types.TOGGLE_FILE_FINDER_VISIBLE, visible);
};

...

[types.TOGGLE_FILE_FINDER_VISIBLE](state, visible) {
  state.fileFinderVisible = visible;
},

@N_Tepluhina

Local mutation + resolver

mutation toggleFileFinder($visible: Boolean!) {
  toggleFileFinder($visible: Boolean!) @client
}

Mutation: {
  checkItem: (_, { visible }, { cache }) => {
    const data = cache.readQuery({ query: fileFinder });
    data.fileFinder.visible = visible;
    cache.writeQuery({ query: fileFinder, data });
  },

@N_Tepluhina

Vuex Apollo
Mapped state Local query
Getters Local query + resolver
Actions +mutations Local mutation + resolver

@N_Tepluhina

Cons

  • verbosity of local resolvers

  • tests coverage

  • lack of best practices

  • cognitive load for developers

@N_Tepluhina

Thank you!

Apollo State Management

By Natalia Tepluhina

Apollo State Management

  • 1,036