DEV Community

loading...
Cover image for Vue 3 State Management using Harlem

Vue 3 State Management using Harlem

andrewcourtice profile image Andrew Courtice ・3 min read

Hi everyone

Recently I shared with you a weather app called Ocula which I built using Vue 3. Today I would like to announce another project I have been working on that was born out of Ocula. The project is called Harlem.

Harlem is a new state management solution for Vue 3 that aims to be intuitive, lightweight, immutable and extensible. I wrote Harlem because I wanted a simple state management solution that I could extend when necessary without having to incur the upfront cost in my bundle size for unused features. To achieve this Harlem is split into 2 distinct categories:

  1. The core package
  2. Plugins that extend core functionality

The core package gives you a nice functional API for managing state in your application by creating stores and using state/getters/mutations to interact with said stores. Let's take a look at an example of how to create a simple store using Harlem:

// store.ts

import {
    createStore
} from '@harlem/core';

const STATE = {
    firstName: 'John',
    lastName: 'Smith'
};

export const {
    state,
    getter,
    mutation,
    on,
    once
} = createStore('user', STATE);
Enter fullscreen mode Exit fullscreen mode

The createStore function returns all the methods necessary to now safely interact with state. By default all access to state is immutable and can only be modified through mutations. This immutability ensures changes to your state are predictable and (most importantly) auditable.

Now that our store is created let's go ahead and define a simple getter for joining the first name and last name to output the user's full name.

// getters.ts

/*
The state parameter here is immutable and cannot be assigned to.
*/
export const fullName = getter('fullname', state => `${state.firstName} ${state.lastName}`);
Enter fullscreen mode Exit fullscreen mode

Let's also define some mutations for updating the first and last name.

// mutations.ts

/*
The <string> generic tells harlem that we are expecting a payload of type string. This is optional and only applicable to TypeScript.

It's also worth noting that the state parameter here is the only place in Harlem that state is mutable.
*/

export const setFirstName = mutation<string>('setFirstName', (state, payload) => {
    state.firstName = payload ?? '';
});

export const setLastName = mutation<string>('setLastName', (state, payload) => {
    state.lastName = payload ?? '';
});
Enter fullscreen mode Exit fullscreen mode

That's all there is to it. You now have managed state that can be imported into Vue components. Here's a quick example of how you could use the above store in a component:

<template>
    <div class="app">
        <h1>Hello {{ fullName }}</h1>
        <input type="text" v-model="firstName" placeholder="First name">
        <input type="text" v-model="lastName" placeholder="Last name">
    </div>
</template>

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

import {
    state,
    fullName,
    setFirstName,
    setLastName
} from './stores/user';

export default defineComponent({

    setup() {
        const firstName = computed({
            get: () => state.firstName,
            set: setFirstName
        });

        const lastName = computed({
            get: () => state.lastName,
            set: setLastName
        });

        return {
            firstName,
            lastName,
            fullName
        };
    }

});
</script>
Enter fullscreen mode Exit fullscreen mode

From here you can extend Harlem through the use of plugins to include Vue devtools integration, server-side rendering, storage sync, transactions, snapshots and resetting.

Head over to the repo to see how to install Harlem, the list of available plugins, or even how to write and publish your own plugin. Alternatively you can go to harlemjs.com to see a live demo.

Thanks for reading and happy coding!

Discussion

pic
Editor guide