The Good, the Bad, and the Ugly in Pinia’s Setup Store

TL; DR

If you really want to call $reset on your store, use option store. If you use setup store, do not think of $reset, at all.

Introduction

Pinia is a state management framework for Vue. It is developed by the core Vue devs.

Vue provides two different approaches to define a component: Composition API and Option API. To me, composition API seems more programmatic and the other one seems more syntactic sugar for non-programmers.

In Pinia world, the unit of a logic is called “store”. It has a set of “states”, “getters”, and “actions”. Just like Vue itself, it provides two different ways to define a store: setup (composition-alike) and option.

Here’s a stupid example for the setup style.

import { computed, ref } from 'vue'
import { defineStore } from 'pinia'

export const useNameStore = defineStore('name', () => {
    const first = ref('')
    const last = ref('')
    const fullName = computed(() => `${first} ${last}`)
    function toUpperCase() {
        first.value = first.value.toUpperCase()
        last.value = last.value.toUpperCase()
    }
    return {
        first,
        last,
        fullName,
        setName,
    }
})

This is the option style.

import { defineStore } from 'pinia'

export const useNameStore = defineStore('name', {
    state: () => ({
        first: '',
        last: '',
    }),
    getters: {
        fullName: (state) => `${state.first} ${state.last}`,
    },
    actions: {
        toUpperCase() {
            this.first = this.first.toUpperCase()
            this.last = this.last.toUpperCase()
        }
    },
})

The Good

In general, setup style gives devs more possibilities. The main advantage is calling watch*() in its definition function body. It means, you can subscribe whatever reactive values in Vue.

The Bad

The setup store doesn’t provide $reset. Well, it does, but the only thing the function does is raising an exception.

Once, I met a legacy code. I got lazy and didn’t want to analyze the reason why $reset was necessary. But it was there, and I needed to port the option store to setup store.

Checking if it was a function is not an option. Because there is a function called $reset in setup store, too.

The only option left is declaring a custom $reset function manually.

    function $reset() {
        first.value = ''
        last.value = ''
    }

It’s already ugly, but I could bear it. I had no time.

But, then I smelled something fishy. The default values are defined in two different places. One is when the states are initialized, and the other is in the $reset function.

The Uglier Workaround

Vue provides some helper function for reactivities. For example, toRefs destructs a reactive object and makes each property reactive.

const defaultName = { first: '', last: '' }
import { computed, ref, toRefs } from 'vue'
import { defineStore } from 'pinia'

export const useNameStore = defineStore('name', () => {
    const { first, last } = toRefs(ref(defaultName))
    const fullName = computed(() => `${first} ${last}`)
    function toUpperCase() {
        first.value = first.value.toUpperCase()
        last.value = last.value.toUpperCase()
    }
    function $reset() {
        ({ first: first.value, last: last.value } = defaultName)
    }
    return {
        first,
        last,
        fullName,
        setName,
    }
})

Conclusion

If you want to use setup style store, just do not think about $reset function at all. In many cases, $reset isn’t even necessary.

By @soundlake in
Tags : #Vue, #Pinia, #frontend,