Vue中强制组件重新渲染的正确方法


Posted in Vue.js onJanuary 03, 2021

有时候,依赖 vue 响应方式来更新数据是不够的,相反,我们需要手动重新渲染组件来更新数据。或者,我们可能只想抛开当前的DOM,重新开始。那么,如何让vue以正确的方式重新呈现组件呢?

强制 Vue 重新渲染组件的最佳方法是在组件上设置:key。 当我们需要重新渲染组件时,只需更 key 的值,Vue 就会重新渲染组件。

这是一个非常简单的解决方案。

当然,你可能会对其他方式会更感兴趣:

  • 简单粗暴的方式:重新加载整个页面
  • 不妥的方式:使用 v-if
  • 较好的方法:使用Vue的内置forceUpdate方法
  • 最好的方法:在组件上进行 key 更改

简单粗暴的方式:重新加载整个页面

这相当于每次你想关闭应用程序时都要重新启动你的电脑。

这种方式或许有用,但这是一个非常糟糕的解决方案,不要这样做,我们来看看更好的方法。

不妥的方式:使用 v-if

v-if指令,该指令仅在组件为true时才渲染。 如果为false,则该组件在DOM中不存在。

来看看,v-if 是怎么工作的,在template中,添加v-if指令:

<template>
 <my-component v-if="renderComponent" />
</template>

在script 中,使用nextTick的方法

<script>
 export default {
  data() {
   return {
    renderComponent: true,
   };
  },
  methods: {
   forceRerender() {
    // 从 DOM 中删除 my-component 组件
    this.renderComponent = false;
    
    this.$nextTick(() => {
     // 在 DOM 中添加 my-component 组件
     this.renderComponent = true;
    });
   }
  }
 };
</script>

上面的过程大致如下:

  1. 刚开始 renderComponent设置为true,因此渲染 my-component 组件
  2. 当我们调用forceRerender时,我们立即将renderComponent设置为false
  3. 我们停止渲染my-component,因为v-if指令现在计算结果为false
  4. 在nextTick方法中将renderComponent设置回true
  5. 当v-if指令的计算结果为true时,再次渲染my-component

在这个过程中,有两个部分比较重要

首先,我们必须等到nextTick,否则我们不会看到任何变化。

在Vue中,一个 tick 是一个DOM更新周期。Vue将收集在同一 tick 中进行的所有更新,在 tick 结束时,它将根据这些更新来渲染 DOM 中的内容。如果我们不等到next tick,我们对renderComponent的更新就会自动取消,什么也不会改变。

其次,当我们第二次渲染时,Vue将创建一个全新的组件。 Vue 将销毁第一个,并创建一个新的,这意味着我们的新my-component将像正常情况一样经历其所有生命周期-created,mounted等。

另外,nextTick 可以与 promise 一起使用:

forceRerender() {
 // 从 DOM 中删除 my-component 组件
 this.renderComponent = false;

 this.$nextTick().then(() => {
  this.renderComponent = true;
 });
}

不过,这并不是一个很好的解决方案,所以,让我们做 Vue 想让我们做的

较好的方法:forceUpdate 方法

这是解决这个问题的两种最佳方法之一,这两种方法都得到了Vue的官方支持。

通常情况下,Vue 会通过更新视图来响应依赖项中的更改。然而,当我们调用forceUpdate时,也可以强制执行更新,即使所有依赖项实际上都没有改变。

下面是大多数人使用这种方法时所犯的最大错误。

如果 Vue 在事情发生变化时自动更新,为什么我们需要强制更新呢?

原因是有时候 Vue 的响应系统会让人感到困惑,我们认为Vue会对某个属性或变量的变化做出响应,但实际上并不是这样。在某些情况下,Vue的响应系统根本检测不到任何变化。

所以就像上一个方法,如果你需要这个来重新渲染你的组件,可能有一个更好的方法。

有两种不同的方法可以在组件实例本身和全局调用forceUpdate:

// 全局
import Vue from 'vue';
Vue.forceUpdate();

// 使用组件实例
export default {
 methods: {
  methodThatForcesUpdate() {
   // ...
   this.$forceUpdate();
   // ...
  }
 }
}

重要提示:这不会更新任何计算属性,调用forceUpdate仅仅强制重新渲染视图。

最好的方法:在组件上进行 key 更改

在许多情况下,我们需要重新渲染组件。

要正确地做到这一点,我们将提供一个key属性,以便 Vue 知道特定的组件与特定的数据片段相关联。如果key保持不变,则不会更改组件,但是如果key发生更改,Vue 就会知道应该删除旧组件并创建新组件。

正是我们需要的!

但是首先,我们需要绕一小段路来理解为什么在Vue中使用key。

为什么我们需要在 Vue 中使用 key

一旦你理解了这一点,那么这是了解如何以正确方式强制重新渲染的很小的一步。

假设我们要渲染具有以下一项或多项内容的组件列表:

  • 有本地的状态
  • 某种初始化过程,通常在created或mounted钩子中
  • 通过jQuery或普通api进行无响应的DOM操作

如果你对该列表进行排序或以任何其他方式对其进行更新,则需要重新渲染列表的某些部分。 但是,不会希望重新渲染列表中的所有内容,而只是重新渲染已更改的内容。

为了帮助 Vue 跟踪已更改和未更改的内容,我们提供了一个key属性。 在这里使用数组的索引,因为索引没有绑定到列表中的特定对象。

const people = [
 { name: 'Evan', age: 34 },
 { name: 'Sarah', age: 98 },
 { name: 'James', age: 45 },
];
如果我们使用索引将其渲染出来,则会得到以下结果:

<ul>
 <li v-for="(person, index) in people" :key="index">
  {{ person.name }} - {{ index }}
 </li>
</ul>

// Outputs
Evan - 0
Sarah - 1
James - 2

如果删除Sarah,得到:

Evan - 0
James - 1

与James关联的索引被更改,即使James仍然是James。 James会被重新渲染,这并不是我们希望的。

所以这里,我们可以使用唯一的 id 来作为 key

const people = [
 { id: 'this-is-an-id', name: 'Evan', age: 34 },
 { id: 'unique-id', name: 'Sarah', age: 98 },
 { id: 'another-unique-id', name: 'James', age: 45 },
];

<ul>
 <li v-for="person in people" :key="person.id">
  {{ person.name }} - {{ person.id }}
 </li>
</ul>

在我们从列表中删除Sarah之前,Vue删除了Sarah和James的组件,然后为James创建了一个新组件。现在,Vue知道它可以为Evan和James保留这两个组件,它所要做的就是删除Sarah的。

如果我们向列表中添加一个person,Vue 还知道可以保留所有现有的组件,并且只需要创建一个新组件并将其插入正确的位置。这是非常有用的,当我们有更复杂的组件,它们有自己的状态,有初始化逻辑,或者做任何类型的DOM操作时,这对我们很有帮助。

所以接下来看看,如果使用最好的方法来重新渲染组件。

更改 key 以强制重新渲染组件

最后,这是强制Vue重新渲染组件的最佳方法(我认为)。

我们可以采用这种将key分配给子组件的策略,但是每次想重新渲染组件时,只需更新该key即可。

这是一个非常基本的方法

<template>
 <component-to-re-render :key="componentKey" />
</template>


export default {
 data() {
  return {
   componentKey: 0,
  };
 },
 methods: {
  forceRerender() {
   this.componentKey += 1; 
  }
 }
}

每次forceRerender被调用时,我们的componentKey都会改变。当这种情况发生时,Vue将知道它必须销毁组件并创建一个新组件。我们得到的是一个子组件,它将重新初始化自身并“重置”其状态。

如果确实需要重新渲染某些内容,请选择key更改方法而不是其他方法。

以上就是Vue中强制组件重新渲染的正确方法的详细内容,更多关于vue 强制组件渲染的资料请关注三水点靠木其它相关文章!

Vue.js 相关文章推荐
在Vue中使用mockjs代码实例
Nov 25 Vue.js
解决vue下载后台传过来的乱码流的问题
Dec 05 Vue.js
vue自定义组件实现双向绑定
Jan 13 Vue.js
如何在Vue项目中添加接口监听遮罩
Jan 25 Vue.js
vue引入Excel表格插件的方法
Apr 28 Vue.js
Vue-Element-Admin集成自己的接口实现登录跳转
Jun 23 Vue.js
vite+vue3.0+ts+element-plus快速搭建项目的实现
Jun 24 Vue.js
Vue实现tab导航栏并支持左右滑动功能
Jun 28 Vue.js
详解gantt甘特图可拖拽、编辑(vue、react都可用 highcharts)
Nov 27 Vue.js
Vue的过滤器你真了解吗
Feb 24 Vue.js
Vue如何清空对象
Mar 03 Vue.js
vue ant design 封装弹窗表单的使用
Jun 01 Vue.js
vue中activated的用法
Jan 03 #Vue.js
vue实现登录功能
Dec 31 #Vue.js
vue 实现图片懒加载功能
Dec 31 #Vue.js
vue 动态创建组件的两种方法
Dec 31 #Vue.js
Vue 修改网站图标的方法
Dec 31 #Vue.js
Vue中inheritAttrs的使用实例详解
Dec 31 #Vue.js
vue导入.md文件的步骤(markdown转HTML)
Dec 31 #Vue.js
You might like
PHP基于正则批量替换Img中src内容实现获取缩略图的功能示例
2017/06/07 PHP
JS 密码强度验证(兼容IE,火狐,谷歌)
2010/03/15 Javascript
input按钮的事件处理大全
2010/12/10 Javascript
十个迅速提升JQuery性能让你的JQuery跑得更快
2012/12/10 Javascript
js计算任意值之间随机数的方法
2015/01/16 Javascript
jQuery插件Tooltipster实现漂亮的工具提示
2015/04/12 Javascript
jQuery取消ajax请求的方法
2015/06/09 Javascript
基于jQuery+PHP+Mysql实现在线拍照和在线浏览照片
2015/09/06 Javascript
Angularjs实现多个页面共享数据的方式
2016/03/29 Javascript
模仿password输入框的实现代码
2016/06/07 Javascript
nodejs搭建本地http服务器教程
2017/03/13 NodeJs
jQuery实现动态添加节点与遍历节点功能示例
2017/11/09 jQuery
JavaScript实现单英文金山打字通
2020/07/24 Javascript
小程序实现横向滑动日历效果
2019/10/21 Javascript
Vuex的实战使用详解
2019/10/31 Javascript
vue.js中使用微信扫一扫解决invalid signature问题(完美解决)
2020/04/11 Javascript
原生js实现放大镜组件
2021/01/22 Javascript
python处理大数字的方法
2015/05/27 Python
python读取文本绘制动态速度曲线
2018/06/21 Python
eclipse创建python项目步骤详解
2019/05/10 Python
Django中间件拦截未登录url实例详解
2019/09/03 Python
Laravel框架表单验证格式化输出的方法
2019/09/25 Python
浅析PEP572: 海象运算符
2019/10/15 Python
Python lxml模块的基本使用方法分析
2019/12/21 Python
使用python3 实现插入数据到mysql
2020/03/02 Python
Python collections模块的使用方法
2020/10/09 Python
字中字效果的实现【html5实例】
2016/05/03 HTML / CSS
可能这些是你想要的H5软键盘兼容方案(小结)
2019/04/23 HTML / CSS
HTML5 textarea高度自适应的两种方案
2020/04/08 HTML / CSS
缓解脚、腿和背部疼痛:Z-CoiL鞋
2019/03/12 全球购物
荷兰音乐会和音乐剧门票订购网站:Topticketshop
2019/08/27 全球购物
小学生优秀评语大全
2014/04/22 职场文书
银行服务理念口号
2015/12/25 职场文书
教你用eclipse连接mysql数据库
2021/04/22 MySQL
如何判断pytorch是否支持GPU加速
2021/06/01 Python
React forwardRef的使用方法及注意点
2021/06/13 Javascript