I have some form data which I share with children components through props. Now I want to clone the prop object and make it non-reactive. In my case I want the user to be able to modify the props value without actually changing the cloned value. The cloned value should only be there to show the user what the form was when editing. Below code shows this:
<template>
<div>
<div v-if="computedFormData">
original prop title: {{orgData.title}}
new title:
<input type="text" v-model="formData.title"/>
//changing data here will also change orgData.title
</div>
</div>
</template>
<script>
export default {
props: ['formData'],
data() {
return {
orgData: [],
}
},
computed: {
computedFormData: function () {
this.orgData = this.formData;
return this.orgData;
},
},
methods: {
},
}
</script>
I have tried with Object.freeze(testData);
but it doesnt work, both testData and orgData are reactive. Note also that using mounted
or created
property does not render orgData so I'm forced to use the computed
property.
Props and data are both reactiveWith Vue you don't need to think all that much about when the component will update itself and render new changes to the screen. This is because Vue is reactive. Instead of calling setState every time you want to change something, you just change the thing!
Bookmark this question.
Try copying the prop values with Object.assign. No more issue with reactivity since the new, assigned values are just the copy instead of the reference to the source.
If your data object is a lot more complex, I'd recommend deepmerge in place of Object.assign
.
Vue.component('FormData', {
template: `
<div>
<div v-if="testData">
<p>Original prop title: <strong>{{orgData.title}}</strong></p>
<p>Cloned prop title:</p>
<input type="text" v-model="testData.title" />
</div>
</div>
`,
props: ['orgData'],
data() {
return {
testData: Object.assign({}, this.orgData)
}
}
});
const vm = new Vue({
el: '#app',
data() {
return {
dummyForm: {
title: 'Some title'
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<form-data :org-data="dummyForm"></form-data>
</div>
Not entirely sure why but using Object.assign
on a computed property did not work for me. I solved it by using a watch property for the props value:
watch:{
formData(){
this.orgData = Object.assign({}, this.formData)
}
},
Object.assign is merely a shallow copy. If you have a copy consists that of only primitive data types (string, number, bigint, boolean, undefined, symbol, and null) it's ok. It to remove its reactivity. But, if you have a copy that has reference types you can’t shallow clone it to remove its reactivity.
For depping clone you can use the JSON.parse(JSON.stringify()) pattern. But keep in mind that is going to work if your data consists of supported JSON data types.
props: ['orgData'],
data() {
return {
cloneOrgData: JSON.parse(JSON.stringify(this.orgData))
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With