Lolo González
Lolo González

Reputation: 31

Array no reactive when modifying an element, only when adding or deleting

I'm doing crud of publications with Vue components and Laravel.

I have one parent component called publications.vue which has 2 childs called create.vue and list.vue, and list.vue I have another to childs called remove.vue and update.vue.

The thing is when I add or remove a publication in the array it works perfect, but when I modify an element it doesn't react. The controller works perfect, but unless I refresh I don't get anything on the screen.

This is my code:

<template>
    <div class="main">
        <create
            :user="user"
            v-if="showCreate"
            @create="addPublicationOnClient"
        />
  
        <list 
            v-for="(publication, index) in publications"
            :key="publication.id" :publication="publication" :user="user" 
            @deleted="deletePublicationOnClient(index)" 
            @updated="updatePublicationOnClient(index, ...arguments)"
        />
    </div>
</template>
addPublication(publication) {
    this.publications.unshift(publication); // works perfect
},

deletePublication(index) {
    this.publications.splice(index, 1); // works perfect
},

updatePublication(index, editedPublication) {
     console.log(editedPublication); // shows the correct value of the edited publication
     
     Vue.set(this.publications, index, editedPublication); // do not react. do not show anything
     this.publications.splice(index, 1, editedPublication) // do not react neither. do not show anything
     
     console.log(this.publications); // shows the correct values in the array
}

I will really appreciate any help because I really stuck and I have read a lot of posts, but can't find a solution.

Upvotes: 1

Views: 434

Answers (1)

Kurt Friars
Kurt Friars

Reputation: 3764

Vue has some really tricky behavior when it comes to arrays of objects.

Vue is watching your array, and when the array's .length is modified or if one of its values is modified vue can "see" that change.

When you update fields of an object in the array you will not get the reactivity, because to Vue the array has not changed. This is because the array's values are references to the object, and when you update the object, those references don't change.

Your approach above seems fine to me, but again there can be really weird issues.

I will highlight two tools to combat these reactivity issues. The first is better for your situation I believe.

  1. Explicitly modify the length of the array.
updatePublication(index, editedPublication) {
    this.deletePublication(index);
    this.addPublication(index, editedPublication);
}
  1. Force re-rendering using :key. When a key changes in a template, it will force re-rendering of all child elements.
<template>
    <div class="main" :key="'updated-'+updated">
    ...
</template>
    data() {
        return {
            updated: 0,
        };
    },

    ...

    updatePublication(index, editedPublication) {
        this.publications.splice(index, 1, editedPublication);
        this.updated++;
    }

Upvotes: 1

Related Questions