Внутреннее состояние компонентов Vue.js повторно используется при изменении базовых данных

Я работаю над веб-приложением среднего размера на основе vue.js. Я столкнулся с несколькими проблемами виртуального DOM, в основном связанными с жизненным циклом экземпляров vue.

Следующий фрагмент кода (jsFiddle также доступен здесь) демонстрирует некоторые из этих проблем. Компонент vue test-component получает значение свойства и обновляет свое внутреннее состояние, используя это значение.

Каждый раз, когда набор данных изменяется (путем сортировки или новыми данными), свойства обновляются, а внутреннее состояние - нет. В этом довольно легко убедиться, запустив фрагмент кода и нажав кнопки.

Я понимаю, что атрибут компонента data - это функция, и похоже, что он вызывается только при создании компонента. Так объясняется, что происходит. Дело в том, что я не знаю, как добиться желаемого поведения, а именно: внутреннее состояние всех дочерних компонентов обновляется при изменении источника данных.

  1. Есть ли обратный вызов жизненного цикла, который срабатывает, когда компонент
    "обновляется"? Мне нужен обратный вызов только для обновления компонента. Нужно ли мне индивидуально следить за изменениями опоры? Это было бы некрасиво.
  2. Есть ли чистый способ обновить внутреннее состояние при изменении реквизита?
  3. Можно ли уничтожить все дочерние компоненты и заставить их воссоздать заново? Я знаю, что это не лучший вариант, но он решит все мои проблемы с привязкой данных :)
  4. Как vue решает, когда компонент будет выпущен или использован повторно? В моем примере компоненты исчезают, когда размер набора данных изменяется с 4 на 3, но внутреннее состояние первых трех элементов не изменяется, поэтому первые три элемента используются повторно.

Перемещение всего состояния в vuex было бы возможным решением, но некоторые компоненты являются общими, и я не хочу, чтобы они содержали информацию о деталях хранилища vuex. На самом деле я использую vuex для большинства компонентов, но для действительно общих компонентов я не думаю, что это хороший вариант.

var testComponent = Vue.component('test-component', {
  template: '#component_template',
  props: ['prop1'],
  data: function(){
    return {
      internalState: this.prop1 
    }
  }
})

new Vue({
  el: "#app",
  data: function(){
    return {
      items: [
        'Item 1',
        'Item 2',
        'Item 3'
      ],
      dataToggle: true,
      sorted: true
    };
  },
  methods: {
    sortDataSet: function(){
      if(this.sorted){
        this.items.reverse();
      } else {
        this.items.sort;
      }
    }
    ,changeDataSet: function(){
      if(this.dataToggle){
        this.items = ['Item 4', 'Item 5', 'Item 6', 'Item 7'];
      } else {
        this.items = ['Item 1', 'Item 2', 'Item 3'];
      }
      
      this.dataToggle = !this.dataToggle;
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.2/vue.js"></script>
<body>
  <h3>
    Components internal state is not being updated
  </h3>
  <div id="app">
    <button v-on:click="changeDataSet">
      Change data
    </button>
    <button v-on:click="sortDataSet">
      Sort data
    </button>
    <ul>
      <li v-for="item in items">
        <test-component :prop1="item">
        </test-component>
      </li>
    </ul>
  </div>
</body>

<script id="component_template" type="x-template">
	<div>Prop: {{prop1}} || Internal state: {{internalState}}</div>
</script>


person Wilson Freitas    schedule 03.05.2017    source источник


Ответы (1)


Используйте ключ.

Рекомендуется по возможности предоставлять ключ с v-for, если только повторяющееся содержимое DOM не является простым или вы намеренно не полагаетесь на поведение по умолчанию для повышения производительности.

<li v-for="item in items" :key="item">
    <test-component :prop1="item">
    </test-component>
</li>

Обновлен скрипка.

person Bert    schedule 03.05.2017
comment
Спасибо, @bertevans. Такое поведение не должно быть по умолчанию. Это противоречит интуиции и может вызывать скрытые ошибки. - person Wilson Freitas; 03.05.2017
comment
@WilsonFreitas Это действительно заставляет многих спотыкаться. - person Bert; 03.05.2017