[Vuejs]-B-table reloads nested components when "unshifting" a new row (but not when "pushing")

2👍

To minimize re-renders of child components in a b-table, and if your data has a field that is unique for every row (i.e. an ID or primary key), set the primary-key prop to the name of the field that contains the unique row ID. This unique ID will be used as the Vue key for each <tr> element. Vue will then know if it needs to re-render the children or not.

Otherwise, what is happening is that b-table uses the row’s index as the key. By pushing new rows on the table, the previous rows’ Vue key stays the same (and hence not re-rendered), but if you shift on the top of the rows, those that previously has indexes of 0, 1, 2, etc have been replaced by new rows… and the entire table and it’s contents (children) must be re-rendered.

EDIT/UPDATE:

I’ve discovered the root cause. The row-details slot was always using the row’s index as its :key, and not incorporating the primary key value (if available). PR https://github.com/bootstrap-vue/bootstrap-vue/pull/4025 will fix this issue and will be available in the 2.0.0 stable release (being released today hopefully).

UPDATE 2:

BootstrapVue v2.0.0 stable has just been released (2019-09-06)

-1👍

I think it has something todo with the child component. If you set _showDetails to true to every element you see what is happening. If you press prepend for the first time the number of the prepend will be the current number of parent and parent gets an new number

<template>
  <div>
    <input value="Append Row" @click="appendRow" type="button">
    <input value="Prepend Row" @click="prependRow" type="button">
    <b-table :items="records" :fields="fields">
      <template v-slot:row-details="scope">
        <child-component :number="scope.item.number"/>
      </template>
    </b-table>
  </div>
</template>

<script>
import ChildComponent from "./ChildComponent";

export default {
  data() {
    return {
      fields: ['name'],
      records: [
        {
          name: "Parent Row",
          _showDetails: true,
          number: Math.random()
        }
      ]
    };
  },
  components: {
    "child-component": ChildComponent
  },
  methods: {
    appendRow() {
      let newRow = {
        name: "New Row (Append)",
        _showDetails: true,
        number: Math.random()
      };
      this.records.push(newRow);
    },
    prependRow() {
      let newRow = {
        name: "New Row (Prepend)",
        _showDetails: true,
        number: Math.random()
      };
      this.records.unshift(newRow);
    }
  }
};
</script>

Child-component:

<template>
  <div>
    <p>test {{number}}</p>
  </div>
</template>

<script>
export default {
  props: ['number'],
  data() {
    return {
      isUpdating: console.log("Updating Child Component")
    };
  }
};
</script>

Leave a comment