I've a component called EditUser.vue
which is linked to a router system using vue router, this is the definition of the route for this component
{
path: "/users/:id/edit",
name: "Edit User",
props: true,
component: () => import(/* webpackChunkName "edit-user" */ "@/views/EditUser.vue"),
beforeEnter: (to, from, next) => {
if (!store.getters.isLogged) next("/");
else next();
}
},
Pretty straightforward with props enable because it needs to get the user id.
The component itself is this
<template>
<main class="h-creen p-3">
<Input
type="text"
name="name"
label="name"
v-model="user.name"
required
/>
</main>
</template>
<script>
import { mapState } from "vuex";
import Input from "@/components/Input.vue";
export default {
name: "EditUserView",
props: {
id: {
required: true,
type: String,
}
},
components: {
Input,
},
data: () => ({
user: {},
}),
async beforeMount() {
// TODO move into router file
if (this.users.length <= 0) {
this.$router.push("/users");
}
this.user = this.users.find(user => user.id == this.id);
},
computed: mapState(["users"])
};
</script>
I've omitted the useless parts, this code replicate the problem anyway. <Input>
is just a wrapper for a label and an input with some styling, nothing magic there.
The problems is that if I type something into the input I expect that this.users
gets modified, which it happens, but it should not modified the same record inside the Vuex state, but that happens and I don't get why. In other words if I edit the name using the input, this modification gets propagated on the state, thus being rendered in other views, but it shouldn't since it's a local data.
What am I missing here?
This results in assigning with a reference to existing object:
this.user = this.users.find(user => user.id == this.id);
When user.name
property is changed with v-model
two-way binding, the respective nested object is modified in users
.
Data should be either shallowly copied to be local (deep copy may be necessary depending on the case):
this.user = {...this.users.find(user => user.id == this.id)};
Then this.user
should be copied back to this.users
when needed.
Or the component shouldn't have its own user
, it can contain separate fields:
<Input
type="text"
name="name"
label="name"
v-model="name"
required
/>
name
, etc. can be copied back to this.users
when needed.