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.