前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >$forceUpdate的解析

$forceUpdate的解析

原创
作者头像
Yerik
发布2022-04-03 10:03:28
9200
发布2022-04-03 10:03:28
举报

在vue的开发过程中,数据的绑定通常来说都不用我们操心,例如在data中有一个msg的变量,只要修改它,那么在页面上,msg的内容就会自动发生变化。但是如果对于一个复杂的对象,例如一个对象数组,直接去给数组上某一个元素增加属性,或者直接把数组的length变成0,vue可能就无法知道发生了改变。这个其实就是考验对于双向绑定的更进一步的理解应用了。

在Vue中,双向绑定属于自动档,然而在特定的情况下,需要手动触发“刷新”操作,目前有四种方案可以选择:

  1. 刷新整个页面
  2. 使用v-if标记
  3. 使用内置的forceUpdate方法
  4. 使用key-changing优化组件

方案分析

本次文章主要重点在于分析forceUpdate这个方法,后续有机会再来分析key-changing

forceUpdate

该方案是比较好的一种方式,比如说我们尝试直接给某个object增加一个属性,发现页面上没有效果;直接将length变成0来清空数组,也没有效果,关键代码如下:

change: function(index) {
    // 增加性格属性
    this.girls[idx].character  = 'lovely';
},
clear: function() { 
    // 清空数组
    this.girls.length = 0;
}

按照上面的写法没有产生想要的效果,是因为没有按照vue的规范去写,因为文档里面写了,对于深层的,最好用$set方法,这样vue就可以知道发生了变化,同时vue也不建议直接修改length,而是给一个空数组来置空。

如果我们按照vue的规范去写的,是可以实现变化的,关键代码如下:

change: function(index) {
    // 增加性格属性
    this.$set(this.girls[idx],'character','lovely')
},
clear: function() {
    // 清空数组
    this.girls = [];
}

如果我们不想利用$set去设置,非要按照我们第一种方式去写,可以实现么?可以的,就是利用$forceUpdate,此时修改了数据,然而页面层没有变动,之后通过日志打印的方式确认数据是否有修改过,之后再确认有没有监听到,用$forceUpdate就相当于按照最新数据给渲染一下。

关键代码如下:

change: function(index) {
    this.girls[idx].character = '男';
    this.$forceUpdate();
},
clear: function() {
    this.girls.length = 0;
    this.$forceUpdate();
}

这种做法实际上并不推荐,官方说如果你现在的场景需要用forceUpdate方法 ,那么99%是你的操作有问题,如上data里不显示声明对象的属性,之后添加属性时正确的做法时用 $set()方法,所以forceUpdate请慎用。

该同等效果的:window.location.reload()

本质

在vue的官方文档中有说明到这个是一个强制刷新的api,但很少用到,除非是遇到了需要实时响应组件状态的时候

Force the component instance to re-render. This should be rarely needed given Vue's fully automatic reactivity system. The only cases where you may need it is when you have explicitly created non-reactive component state using advanced reactivity APIs.

实现原理

Vue.prototype.$forceUpdate = function () {
    const vm: Component = this
    if (vm._watcher) {
        vm._watcher.update()
    }
}

实例需要重新渲染是在依赖发生变化的时候会通知watcher,然后通知watcher来调用update方法,就是这么简单。

分析

forceUpdate就是重新render

  • 有些变量不在state上,但是你又想达到这个变量更新的时候,重新(render),从而渲染虚拟DOM。
    • 注意到这个时候并不是重新加载组件。
    • 结合vue的生命周期,调用$forceUpdate后只会触发beforeUpdateupdated这两个钩子函数,不会触发其他的钩子函数。它仅仅影响实例本身和插入插槽内容的子组件,而不是所有子组件,即强制更新因某些原因并未渲染到页面的,已经改变的,应该被渲染到页面的数据
  • state里的某个变量层次太深,更新的时候没有自动触发render

这些时候都可以手动调用 forceUpdate 自动触发 render 。所以建议使用immutable来操作statereduxflux 架构来管理state

刷新页面

这个方案是挺low的,本质上是刷新页面

this.$router.go(0)

使用v-if标记

如果是刷新某个子组件,则可以通过v-if指令实现。我们知道,当v-if的值发生变化时,组件都会被重新渲染一遍。因此,利用v-if指令的特性,可以达到强制刷新组件的目的。

<template>
    <compare v-if="refresh"></compare>
    <el-button @click="refreshComp()">刷新comp组件</el-button>
</template>
<script>
import compare from '@/views/compare.vue'
export default {
    name: 'parentComp',
    data() {
        return {
            refresh: true
        }
    },
    methods: {
        refreshComp() {
            // 移除组件
            this.refresh = false
            // 在组件移除后,重新渲染组件
            // this.$nextTick可实现在DOM 状态更新后,执行传入的方法。
            this.$nextTick(() => {
                this.refresh = true
            })
        }
    }
}
</script>

key-changing

原理很简单,vue使用key标记组件身份,当key改变时就是释放原始组件,重新加载新的组件。

<template>
  <div>
    <span :key="key"></span>
  </div>
</template>
<script>
  export default {
    data() {
      return {
        key: 0
      }
    },
    methods: {
      handleUpdateClick() {
        this.key += 1 // 或者 this.key = new Date();
      }
    }
  }
</script>

参考资料

  1. https://vuejs.org/api/component-instance.html#forceupdate
  2. https://www.cnblogs.com/YiFeng-Liu/p/14835986.html

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 方案分析
    • forceUpdate
      • 本质
      • 实现原理
      • 分析
    • 刷新页面
      • 使用v-if标记
        • key-changing
        • 参考资料
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档