Search code examples
javascriptvue.jspinia

How to bind dropdown value to Pinia state in Vue


I am trying to bind a Pinia state value to a dropdown, and also have this dropdown mutate the state. I think my approach is causing a circular reference with a computed variable. The onChange() function isn't actually changing the state.

This is my component:

<script setup>

import { useMyStore } from '@/stores/myStore';
import { computed } from 'vue';

const myStore = useMyStore();

// convert the stored value to string for dropdown
const dropdownVal = computed(() => {
    const stringVal = myStore.numVal.toString();
    return stringVal
})

// I think this is the issue 
const onChange = () =>{
    myStore.numVal = parseInt(dropdownVal.value);
}

</script>

<template>
<select v-model="dropdownVal" @change="onChange()">
<option value='1'>Option 1</option>
<option value='2'>Option 2</option>
<option value='3'>Option 3</option>
</select>
</template>

I have another component that also modifies myStore.numVal and I need this to be reflected in the dropdown when state changes (It's just using a .$reset()).


Solution

  • Thanks to @entio for the comment, I was able to achieve what I wanted with the following:

    I had to use storeToRefs() in order to maintain reactivity within the computed variable.

    <script setup>
    
    import { useMyStore } from '@/stores/myStore';
    import { computed } from 'vue';
    import { storeToRefs } from 'pinia';
    
    const myStore = storeToRefs(useMyStore());
    
    // convert the stored value to string for dropdown
    const dropdownVal = computed(() => {
        const stringVal = myStore.numVal.value.toString();
        return stringVal
    })
    
    // I think this is the issue 
    const onChange = () =>{
        myStore.numVal.value = parseInt(dropdownVal.value);
    }
    
    </script>
    
    <template>
    <select v-model="myStore.numVal.value" @change="onChange()">
    <option value='1'>Option 1</option>
    <option value='2'>Option 2</option>
    <option value='3'>Option 3</option>
    </select>
    </template>