Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deep copy of a Javascript object is not working as expected in Vue.js

I am passing a clone of an object from a parent component to a child component using props, but when I change the value of the status property in the object of the parent component the child component gets notified and chenges the value of the status property in the "cloned" object.

I've read about Object.assign() method and that it only does shallow copying but the strange thing is that my object properties are of primitive type String meaning they should be copied by value not by reference, I even tried assigning the values manually and tried the JSON way as demonstrated below but nothing works as I expected.

Parent Component: AppServers

<template>
  <div>
    <AppServerStatus v-for="server in servers"   :serverObj="JSON.parse(JSON.stringify(server))">
    </AppServerStatus>
    <hr>
    <button @click="changeStatus()">Change server 2</button>
  </div>
</template>

<script>
  import AppServerStatus from './AppServerStatus';

  export default {
    name: "AppServers",
    components: {
      AppServerStatus
    },
    data() {
      return {
        servers: [
          {
            name: 'server1',
            status: 'Critical'
          },
          {
            name: 'server2',
            status: 'Normal'
          },
          {
            name: 'server3',
            status: 'abnormal'
          },
          {
            name: 'server4',
            status: 'idle'
          },
          {
            name: 'server5',
            status: 'Good'
          },
        ],
        serverTmp: {}
      }
    },
    methods: {
      changeStatus(){
        this.servers[1].status = 'Active';
      }
    }
  }
</script>

Child Component: AppServerStatus

<template>
  <div>
    <h3>Server Name: {{ serverObj.name }}</h3>
    <p>Server Status: {{ serverObj.status }}</p>
    <hr>
  </div>
</template>

<script>
  export default {
    name: "AppServerStatus",
    data() {
      return {
        status: 'Critical'
      }
    },
    props: [
      'serverObj'
    ]
  }
</script>

I expect the value of status property in the object of the child component to stay Normal when I execute changeStatus() in the parent component but it changes also.

like image 340
Majd Warraq Avatar asked May 24 '19 13:05

Majd Warraq


1 Answers

Create a new object from the serverObj prop on created or mounted to prevent unwanted reactivity.

<template>
  <div>
    <h3>Server Name: {{ server.name }}</h3>
    <p>Server Status: {{ server.status }}</p>
    <hr>
  </div>
</template>

<script>
  export default {
    name: 'AppServerStatus',
    data() {
      return {
        status: 'Critical',
        server: {
          name: '',
          status: ''
        }
      }
    },

    props: [
      'serverObj'
    ],

    mounted() {
       this.server = {
         name: this.serverObj.name,
         status: this.serverObj.status
       };
    }
  }
</script>

like image 90
Jack Avatar answered Nov 10 '22 01:11

Jack