Vue.js 组件内部状态在底层数据更改时被重用

Posted

技术标签:

【中文标题】Vue.js 组件内部状态在底层数据更改时被重用【英文标题】:Vue.js components internal state being reused when underlying data changes 【发布时间】:2017-10-01 14:09:34 【问题描述】:

我正在开发一个基于 vue.js 的中型 Web 应用程序。我一直面临着几个主要与 vue 实例生命周期有关的虚拟 DOM 问题。

以下代码 sn-p(jsFiddle 也可用 here)演示了其中的一些问题。 test-component vue 组件接收一个属性值并使用该值更新其内部状态。

只要数据集发生变化(通过排序或新数据),属性就会更新,但内部状态不会。这很容易通过运行代码 sn-p 并单击按钮来查看。

我了解 data 组件属性是一个函数,看起来它仅在创建组件时才被调用。这种解释是怎么回事。问题是我不知道如何实现预期的行为:所有子组件的内部状态都会在数据源更改时更新

    是否有在组件被触发时触发的生命周期回调 “刷新”?我想要一个仅刷新组件的回调。我需要单独观察道具变化吗?那会很丑。 有没有一种干净的方法可以在 props 更改时更新内部状态? 是否可以销毁所有子组件并强制重新创建它们?我知道这不是最好的选择,但它可以解决我所有的数据绑定问题:) vue 如何决定何时发布或重用组件?在我的示例中,当数据集大小从 4 变为 3 时,组件会消失,但前 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>

【问题讨论】:

【参考方案1】:

使用key。

建议尽可能提供带有 v-for 的键, 除非迭代的 DOM 内容很简单,或者你是故意的 依靠默认行为来提高性能。

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

更新fiddle。

【讨论】:

谢谢@bertevans 这种行为不应该是默认行为。这是反直觉的,可能会导致隐藏的错误。 @WilsonFreitas 这确实会导致很多人绊倒。

以上是关于Vue.js 组件内部状态在底层数据更改时被重用的主要内容,如果未能解决你的问题,请参考以下文章

Vue.js 中父级数据更改时如何重新渲染内部组件

Vue.js - 从 API 获取数据并在 Vuex 状态更改时重新加载组件

Vue.js:从其方法内部更改组件道具的正确方法

Vue.js- Vuex 更新数组中的对象,内部状态未反映在组件 DOM 中

Vue.js2:如何重用组件内定义的常量

使用 Vue.js 创建可重用的按钮组件