Vue3 - 快取(Cache)組件

tags: Vue
category: Front-End
description: Vue3 - 快取(Cache)組件<KeepAlive>
created_at: 2022/07/22 14:00:00

cover image


回到 手把手開始寫 Vue3


前言

這次要提的是快取組件,先提一下因為是快取,他並不是真的每次都重新掛上新的,所以可能會有舊的資料在上面,要自己記得做處理。


快取組件

首先先來試試組件的快取

要快取組件的話會使用 <KeepAlive> 這個內建組件,這個組件可以讓包住的組件做動態切換的時候做緩存。

然後要注意的點是: 這個組件只能有一個子元素

也就是說它的使用方式是這樣

<KeepAlive>
  <component :is="targetComponent" />
</KeepAlive>

或是如果你硬要的話,也可以這樣

<KeepAlive>
  <A v-if="targetComponent === 'A'"></A>
  <B v-else-if="targetComponent === 'B'"></B>
  <C v-else-if="targetComponent === 'C'"></C>
  <!-- ... -->
</KeepAlive>

補充: 下面這樣是不行的喔!

<KeepAlive>
  <A v-if="targetComponent === 'A'"></A>
  <B v-if="targetComponent === 'B'"></B>
  <C v-if="targetComponent === 'C'"></C>
  <D v-if="targetComponent === 'D'"></D>
  <E v-if="targetComponent === 'E'"></E>
  <F v-if="targetComponent === 'F'"></F>
</KeepAlive>

雖然看也知道他其實只會同時符合一個條件,但是他在編譯的時候就會噴掉了。

因為在一般情況下確實有可能使用 v-if 同時有多個成立,但 else-if 就不同了。


指定哪些(要/不要)快取

可以用 includeexclude 兩個屬性來定義,可以放入逗號分隔的字串、陣列或是一個正規表達式 RegExp

這邊比較簡單,就直接貼官方的範例吧:

<!-- comma-delimited string -->
<KeepAlive include="a,b">
  <component :is="view" />
</KeepAlive>

<!-- regex (use `v-bind`) -->
<KeepAlive :include="/a|b/">
  <component :is="view" />
</KeepAlive>

<!-- Array (use `v-bind`) -->
<KeepAlive :include="['a', 'b']">
  <component :is="view" />
</KeepAlive>

指定快取數量

使用 max 屬性指定快取的數量,而他的行為是 LRU Cache,如果數量超過就會把最近最少使用的刪掉。

舉個例子:

<script setup>
import { shallowRef } from "vue";
import A from "./components/A.vue";
import B from "./components/B.vue";
import C from "./components/C.vue";
import D from "./components/D.vue";
import E from "./components/E.vue";
import F from "./components/F.vue";

const components = [A, B, C, D, E, F];
const targetComponent = shallowRef(components[0]);
</script>

<template>
  <div class="flex">
    <button
      class="bg-blue-500 text-white px-4 py-2 m-2"
      v-for="component in components"
      :key="component.__name"
      @click="targetComponent = component"
    >
      {{ component.__name }}
    </button>
  </div>
  <hr />
  <KeepAlive max="4">
    <component :is="targetComponent" />
  </KeepAlive>
</template>

然後那個 components/A.vuecomponents/F.vue 都長成這樣

<script setup>
import { onMounted, onUnmounted } from "vue";

onMounted(() => {
  console.log("onMounted", "A");
});

onUnmounted(() => {
  console.log("onUnmounted", "A");
});
</script>

<template>
  <div>Component A</div>
  <div>
    <input class="border" type="text" />
  </div>
</template>

只要修改對應的地方,分辨得出來誰是誰就好。

然後因為上面設定的 max="4",所以當你照著這個順序戳

A -> B -> C -> D(到此時空間已滿) -> E(A會被彈出) -> B -> F(這時C會被彈出)

onMounted A
onMounted B
onMounted C
onMounted D
onUnmounted A
onMounted E
onUnmounted C
onMounted F

如果要講更細的話,一樣的範例:

空間 4,順序 A->B->C->D->E->B->F

LRU


生命週期

看上面的範例會發現被快取的組件就不會再次觸發 onMountedonUnmounted 了,那還是想知道他被掛上去跟被拿掉呢?

可以使用 onActivatedonDeactivated

我自己玩下來的感覺是這樣的,

onMounted 的時候會一起觸發 onActivated

但是 onDeactivatedonUnmounted 不一定會一起觸發。

因為 onMountedonActivated 都是被掛上去的時候。

onDeactivatedonUnmounted 雖然都是被拿掉的時候,但是 onUnmounted 是在快取中也不見了才會被呼叫到。

一樣以上面的順序戳一次 A->B->C->D->E->B->F

我只幫元件 A 加上 onActivatedonDeactivated,會看到輸出:

onMounted A
onActivated A
onDeactivated A
onMounted B
onMounted C
onMounted D
onUnmounted A
onMounted E
onUnmounted C
onMounted F

你會看到說 onMountedonActivated 一起。

然後 onUnmounted 並沒有跟 onDeactivated 一起輸出。





最後更新時間: 2022年07月22日.