Shallow copy vs. Deep copy
Object.assign
only creates a shallow copy, so your copy of user
would still refer to any nested object values of the original user
object, as shown in the demo below:
const orig = {
age: 21,
name: {
first: 'John',
last: 'Doe'
},
username: 'jdoe_11',
}
const copy = Object.assign({}, orig) // or: const copy = { ...orig }
// both `name` properties refer to the *same* nested object
console.log('copy.name === orig.name =>', copy.name === orig.name) // => true
copy.name.first = 'Bob'
console.log('orig.name.first =>', orig.name.first) // => 'Bob'
If you want to make a deep copy that is isolated from the original object, I recommend using a utility, such as lodash.cloneDeep
, which recursively copies objects, including all nested properties:
const orig = {
age: 21,
name: {
first: 'John',
last: 'Doe'
},
username: 'jdoe_11',
}
const copy = _.cloneDeep(orig)
console.log('copy.name === orig.name =>', copy.name === orig.name) // => false
copy.name.first = 'Bob'
console.log('orig.name.first =>', orig.name.first) // => 'John'
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
Vuex solution
The Vuex docs discuss the solution to your scenario.
The "Vuex way" to deal with it is binding the <input>
's value and call an action on the input
or change
event:
<input :value="message" @input="updateMessage">
// ...
computed: {
...mapState({
message: state => state.obj.message
})
},
methods: {
updateMessage (e) {
this.$store.commit('updateMessage', e.target.value)
}
}
And here's the mutation handler:
// ...
mutations: {
updateMessage (state, message) {
state.obj.message = message
}
}
Two-way Computed Property
Admittedly, the above is quite a bit more verbose than v-model
+ local state, and we lose some of the useful features from v-model
as well. An alternative approach is using a two-way computed property with a setter:
<input v-model="message">
// ...
computed: {
message: {
get () {
return this.$store.state.obj.message
},
set (value) {
this.$store.commit('updateMessage', value)
}
}
}
If the recommended solution above were infeasible, you could disable Vuex's strict mode as a last resort. Note that strict mode is a development tool that prevents unintentional state changes outside of mutation handlers, so care should be taken in disabling it:
// store.js
export default new Vuex.Store({
// ...
strict: false // disable strict mode
})