Vue 3 State Management using Harlem
Tags: vue, typescript, javascript, webdev
Published: 2020-11-07 05:26:05

Hi everyone

Recently I shared with you a weather app called [Ocula](https://github.com/andrewcourtice/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](https://github.com/andrewcourtice/ocula). The project is called [Harlem](https://github.com/andrewcourtice/harlem).

[Harlem](https://github.com/andrewcourtice/harlem) is a new state management solution for Vue 3 that aims to be intuitive, lightweight, immutable and extensible. I wrote [Harlem](https://github.com/andrewcourtice/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](https://github.com/andrewcourtice/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](https://github.com/andrewcourtice/harlem):

```typescript
// store.ts

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

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

export const {
    state,
    getter,
    mutation,
    on,
    once
} = createStore('user', STATE);
```

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.

```typescript
// getters.ts

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

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

```typescript
// 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 ?? '';
});
```

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:

```html
<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>
```

From here you can extend Harlem through the use of plugins to include [Vue devtools integration](https://github.com/andrewcourtice/harlem/blob/main/plugins/devtools), [server-side rendering](https://github.com/andrewcourtice/harlem/blob/main/plugins/ssr), [storage sync](https://github.com/andrewcourtice/harlem/blob/main/plugins/storage), [transactions](https://github.com/andrewcourtice/harlem/blob/main/plugins/transaction), [snapshots](https://github.com/andrewcourtice/harlem/blob/main/plugins/snapshot) and [resetting](https://github.com/andrewcourtice/harlem/blob/main/plugins/reset).

Head over to the [repo](https://github.com/andrewcourtice/harlem) 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](https://harlemjs.com) to see a live demo.

Thanks for reading and happy coding!