0

I'm sending from the parent component a prop: user. Now in the child component I want to make a copy of it without it changing the prop's value.

I tried doing it like this:

export default defineComponent({
  props: {
    apiUser: {
      required: true,
      type: Object
    }
  },
  setup(props) {
    const user = ref(props.apiUser);

    return { user };
  }
});

But then if I change a value of the user object it also changes the apiUser prop. I thought maybe using Object.assign would work but then the ref isn't reactive anymore.

In Vue 2.0 I would do it like this:

export default {
  props: {
     apiUser: {
       required: true,
       type: Object
     }
  },
  data() {
    return {
      user: {}
    }
  },
  mounted() {
    this.user = this.apiUser;
    // Now I can use this.user without changing this.apiUser's value.
  }
};

Credits to @butttons for the comment that lead to the answer.

const user = reactive({ ...props.apiUser });

4

2 回答 2

6
props: {
 apiUser: {
   required: true,
   type: Object
 }
},
setup(props) {
   const userCopy = toRef(props, 'apiUser')
}

With the composition API we have the toRef API that allows you to create a copy from any source reactive object. Since the props object is a reactive, you use toRef() and it won't mutate your prop.

于 2021-06-03T11:03:58.197 回答
0

As discussed in comment section, a Vue 2 method that I'm personally fond of in these cases is the following, it will basically make a roundtrip when updating a model.

Parent (apiUser) ->
Child (clone apiUser to user, make changes, emit) ->
Parent (Set changes reactively) ->
Child (Automatically receives changes, and creates new clone)

Parent

<template>
   <div class="parent-root"
      <child :apiUser="apiUser" @setUserData="setUserData" />
   </div>
</template>

// ----------------------------------------------------
// (Obviously imports of child component etc.)
export default {
   data() {
      apiUser: {
         id: 'e134',
         age: 27
      }
   },

   methods: {
      setUserData(payload) {
         this.$set(this.apiUser, 'age', payload);
      }
   }
}

Child

<template>
   <div class="child-root"
      {{ apiUser }}
   </div>
</template>

// ----------------------------------------------------
// (Obviously imports of components etc.)
export default {
   props: {
      apiUser: {
         required: true,
         type: Object
      }
   },

   data() {
      user: null
   },

   watch: {
      apiUser: {
         deep: true,
         handler() {
            // Whatever clone method you want to use
            this.user = cloneDeep(this.apiUser);
         }
      }
   },

   mounted() {
      // Whatever clone method you want to use
      this.user = cloneDeep(this.apiUser);
   },

   methods: {
      // Whatever function catching the changes you want to do
      setUserData(payload) {
         this.$emit('setUserData', this.user);
      }
   }
}

Apologies for any miss types

于 2020-08-25T14:41:46.870 回答