Is it OK to modify props if they come from a Pinia store?

Viewed 23

I usually use Vue2 to just quickly knock up a single file app. I am now using vue3, mulitiple components and pinia.

It would really help for someone to explain the basics of components to me, with regard to updating a store.

My limited experience of using components is that you never update the props. That said, I have an app (bare bones below) where I am using v-model successfully on the props.

I have a Form, and have created the following state for it:

    import { defineStore } from "pinia";

    export default defineStore("form", {
        state: () => ({
            screens: [
                {
                    fields: [
                        { type: "text", name: "name" },
                        { type: "email", name: "email" },
                    ],
                },
                {
                    fields: [
                        { type: "number", name: "age" },
                        { type: "date", name: "start_date" },
                    ],
                },
            ],
        }),
    });

Now in my form component, I plan on having something like this:

<template>
  <h1>Create a form</h1>
  <div class="stack form">
    <AdminScreen
      v-for="(screen, s) in form.screens"
      :key="`screen-${s}`"
      class="admin-screen"
    >
      <AdminField
        v-for="(field, f) in screen.fields"
        :key="`field-${f}-${s}`"
        :field="field"
      />
    </AdminScreen>
  </div>
</template>

<script setup>
import useFormStore from "../../useFormStore.js";
import AdminField from "../../components/AdminField.vue";
import AdminScreen from "../../components/AdminScreen.vue";

const form = useFormStore();
</script>

This renders nicely, and in my AdminField I use v-model:

<label :for="`label-${id}`">Label</label>
<input
          :id="`label-${id}`"
          type="text"
          v-model="field.label"
          @change="setKey()"
/>

In my @change function I'd like to create a key if one doesn't exist, so now I am doing things like this:

const setKey = () => {
  if (!props.field.key) {
    props.field.key = lettersAndNumbersOnly(props.field.label)
      .toLowerCase()
      .trim()
      .replaceAll(" ", "_");
  }
};

So here I am directly modifying the props, not even through v-model. This all works great, I'm just a bit worried after reading things like this: https://vuejs.org/guide/components/props.html#one-way-data-flow

Can anyone advise if what I'm doing OK, or if not, the best way to refactor what I have? I looked into mutations, but I couldn't work out if I should be passing a unique id or something to the AdminField, then mutating the store from there, or if I should be $emitting like I used to in Vue2, then adding some very complex listener to the component node like <AdminField @updated="$store.commit({screenIndex: s, fieldIndex: f})" /> to then update the store.

I have also asked this on the Pinia github discussions but with no input.

0 Answers
Related