Vue之重新渲染组件的正确方式

原文:https://michaelnthiessen.com/force-re-render/
以下为翻译篇,如有不正确之处还望留言指正。

当你只想重新渲染某个组件,或者销毁当前DOM并重新开始, 这个时候Vue的响应系统就差点儿意思。那如果是你遇到类似情况的话,会怎么办呢?

最行之有效的办法就是给component设置一个:key,当你需要重新渲染这个组件的时候只需要修改key的值即可。

这难道不是一个相当简单的解决办法吗?

还有一些其他的方法可以实现相同的效果:

  • reloading整个页面 【最差的一种方式】
  • 使用v-if【一般的方式】
  • forceUpdate【比较好的方式】
  • key-changing 【最好的方式】

如果你想强制重新加载或者强制更新,下面会可能是比较好的方式。
很有可能你对相面的几件事情比较迷惑:
1、Vue的响应式
2、计算属性
3、监听器
4、v-for未使用:key

这里有几个强制刷新的可用Demo,大部分都可以通过key-changing方式解决,关于技术的原理在文章的末尾。

reloading整个页面

这是一种类似于“你每次想退出app时都要通过重启电脑”的方式。
我猜想这种方式有时也会很有效,但是确实是个比较糟糕的方式,这里就不必多言,不要这么干了,可以看看其他比较好的方式。

v-if

Vue的v-if指令只有当true时才会显示,false则会将其从DOM中剔除,接下来我们来看看怎么做的。

<template>
  <my-component v-if="renderComponent"/>
</template>
<script>
  export default {
    data() {
      return {
        renderComponent: true,
      };
    },
    methods: {
      forceRerender() {
        // Remove my-component from the DOM
        this.renderComponent = false;

        this.$nextTick(() => {
          // Add the component back in
          this.renderComponent = true;
        });
      }
    }
  };
</script>

流程分析:
1、初始化的时候renderComponent值为true,组件渲染
2、当我们调用forceRerender时,renderComponent会立刻变为false,
3、这个时候因为值为false组件就会停止渲染,
4、然后在next tick里面将renderComponent的值重新设置回去,
5、现在组件就会开始重新渲染
上面的流程主要有两个重要的点需要理解:
1、必须要在nextTick以后才能更改,否则会看不到效果
在Vue中,DOM的更新周期即为一个tick,在同一个tick内Vue会搜集变化,然后在tick的最后会根据变化的值去更新节点,如果我们不等到next tick,直接更新变量的值,不会触发节点的更新。
2、当我们重新渲染的时候,Vue将会创建一个新的组件。Vue销毁之前的重新创建新的意味着新的组件会重新走一遍生命周期。

forceUpdate

和前面的方式对比,这种也是官方支持的、比较好的方式。
正常来讲,Vue会根据依赖的值变化去更新界面,当然,如果你调用forceUpdate,就算依赖的值未变化也会强制更新。
这里有个问题:Vue既然能根据值的变化去自动更新,那为啥我们还需要强制更新呢?这个是因为有的时候Vue的响应系统会有困惑,我们认为Vue会根据某些属性或变量的值变化去更新,结果并没有,而且还有一些其他的情况是响应系统检测不到的。所以如果你有重新渲染组件的需要时这种方式比较好。
需要注意的是:forceUpdate只会强制更新页面,不会更新现有的计算属性。

key-changing

在很多种情况下你可能都会有重新渲染组件的需求,为了比较好的解决这种问题,我们将使用key属性以便Vue能够将数据和组件建立起关系。如果key不变,就不更新。一旦key发生变化,Vue就会剔除旧的创建新的组件。
使用之前我们先看一下为什么要使用key!
当你明白了这个问题以后你对如果正确的重新渲染组件会有不小的进步。
假设您要呈现的组件列表具有以下一个或多个特点:

  • 自有属性
  • 初始化处理,比如在created或者mounted钩子函数中
  • 通过jQuery或者APIs的非响应式DOM操作

如果你对这个列表进行排序或者更新,你都需要重新渲染列表的部分界面,但是你不想将整个列表重新渲染,而仅仅是将修改的过的进行更新。
为了帮助Vue框架能够监测哪些值发生改变,哪些值未变,我们提供了key属性,因为在列表的特殊对象和其索引index没有进行绑定,
这儿有个例子:

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会被重新渲染,虽然我们不想那样。
所以在这里,我们想用某种独特的ID,但是我们最终生成它。

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为了另外两个先删除组件,然后再给James创建一个组件,现在Vue知道可以保留EvanJames组件,唯一需要做的就是删除Sarah的组件.

如果再加上一个人到列表中,它也知道它可以保持现有的所有组件,并且它只能建立一个新的组件,并将其插入正确的位置。这是非常有用的,并帮助了我们很多的时候,我们有更复杂的组件都有自己的状态,必须初始化逻辑,或做任何类型的DOM操作。

也许这弯路也没那么短。但是,有必要解释Vue是如何工作的很关键。

不管怎么说,让我们与强迫重新渲染的最佳方法!
Key-changing to force re-renders of a component

这里是做的一个非常基本的方法:

<template>
  <component-to-re-render :key="componentKey" />
</template>
export default {
  data() {
    return {
      componentKey: 0,
    };
  },
  methods: {
    forceRerender() {
      this.componentKey += 1;
    }
  }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容