Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to clone props object and make it non-reactive

Tags:

vue.js

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.

like image 668
A.C Avatar asked Jan 07 '19 16:01

A.C


People also ask

Are Props reactive?

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!

Are Props reactive Vue 3?

Bookmark this question.


3 Answers

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>
like image 197
Yom T. Avatar answered Oct 17 '22 22:10

Yom T.


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)
        }
    },
like image 39
A.C Avatar answered Oct 17 '22 22:10

A.C


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))
    }
  }
like image 2
Victor Avatar answered Oct 17 '22 21:10

Victor