07 一些API 和 Vue3 新元件

songxia777發表於2024-04-17

shallowRef 與 shallowReactive

透過使用 shallowRef()shallowReactive() 來繞開深度響應。

淺層式 API 建立的狀態只在其頂層是響應式的,對所有深層的物件不會做任何處理,避免了對每一個內部屬性做響應式所帶來的效能成本,這使得屬性的訪問變得更快,可提升效能

shallowRef

建立一個響應式資料,但只對頂層屬性進行響應式處理
只跟蹤引用值的變化,不關心值內部的屬性變化

ref 既可以跟蹤引用值的變化,也可以跟蹤值內部的屬性變化

<template>
  <h2>數值:{{ num }}</h2>
  <h2>姓名:{{ person.name }}</h2>
  <h2>年齡:{{ person.age }}</h2>
  <button @click="changeNum">修改數值</button>
  <button @click="changeName">修改名稱</button>
  <button @click="changeAge">修改年齡</button>
  <button @click="changePerson">修改整個值</button>
</template>

<script lang="ts" setup>
import { ref, shallowRef } from 'vue';
let num = shallowRef(10);
let person = shallowRef({
  name: '張三',
  age: 18,
});

// ref可修改 shallowRef可修改
function changeNum() {
  num.value += 1;
}
// ref可修改 shallowRef 不可修改
function changeName() {
  person.value.name += '~';
}
// ref可修改 shallowRef 不可修改
function changeAge() {
  person.value.age += 2;
}
// ref可修改  shallowRef 可修改
function changePerson() {
  person.value = { name: '新名字', age: 90 };
}
</script>

shallowReactive

建立一個淺層響應式物件只會使物件的最頂層屬性變成響應式的,物件內部的巢狀屬性則不會變成響應式的

物件的頂層屬性是響應式的,但巢狀物件的屬性不是

注意:reactive 定義的資料不可以直接整個修改,需要藉助 Object.assign

<template>
  <h2>姓名:{{ person.name }}</h2>
  <h2>年齡:{{ person.age }}</h2>
  <h2>喜歡的顏色:{{ person.hobby.color }}</h2>
  <h2>喜歡的食物:{{ person.hobby.food }}</h2>
  <button @click="changeName">修改名稱</button>
  <button @click="changeAge">修改年齡</button>
  <button @click="changeColor">修改顏色</button>
  <button @click="changeFood">修改食物</button>
  <button @click="changePerson">修改整個值</button>
</template>

<script lang="ts" setup>
import { reactive, shallowReactive } from 'vue';
let person = shallowReactive({
  name: '張三',
  age: 18,
  hobby: {
    color: '紅色',
    food: '饅頭',
  },
});

// reactive可以修改所有的屬性
// shallowReactive 只會修改物件最頂層屬性,物件內部的巢狀屬性則不會變化

//  shallowReactive 可修改
function changeName() {
  person.name += '~';
}
//  shallowReactive 可修改
function changeAge() {
  person.age += 2;
}

//  shallowReactive 不可修改 物件內部的巢狀屬性
function changeColor() {
  person.hobby.color += '~';
}
//  shallowReactive 不可修改 物件內部的巢狀屬性
function changeFood() {
  person.hobby.food += '~';
}

//  shallowReactive 可修改 修改整體
function changePerson() {
  person = Object.assign(person, {
    name: '張三000',
    age: 180000,
    hobby: {
      color: '紅色000',
      food: '饅頭000',
    },
  });
}
</script>

readonly 和 shallowReadonly

readonly

  1. 作用:用於建立一個物件或基本型別的深只讀副本。

  2. 用法:

    const original = reactive({ ... });
    const original = ref(...);
    const readOnlyCopy = readonly(original);
    
  3. 特點:

    • 物件的所有巢狀屬性都將變為只讀。
    • 任何嘗試修改這個物件的操作都會被阻止(在開發模式下,還會在控制檯中發出警告)。
  4. 應用場景:

    • 建立不可變的狀態快照。
    • 保護全域性狀態或配置不被修改。

shallowReadonly

  1. 作用:與 readonly 類似,但只作用於物件的頂層屬性。

  2. 用法:

    const original = reactive({ ... });
    const shallowReadOnlyCopy = shallowReadonly(original);
    
  3. 特點:

    • 只將物件的頂層屬性設定為只讀,物件內部的巢狀屬性仍然是可變的。

    • 適用於只需保護物件頂層屬性的場景。

toRaw 與 markRaw

toRaw

用於獲取一個響應式物件的原始物件, toRaw 返回的物件不再是響應式的,不會觸發檢視更新。

何時使用:
在需要將響應式物件傳遞給非 Vue 的庫或外部系統時,使用 toRaw 可以確保它們收到的是普通物件

官網描述:這是一個可以用於臨時讀取而不引起代理訪問/跟蹤開銷,或是寫入而不觸發更改的特殊方法。不建議儲存對原始物件的持久引用,請謹慎使用

isReactive 可以判定是否是響應式物件

import { reactive, toRaw, isReactive } from 'vue';

// 響應式物件
let person = reactive({ name: 'tony', age: 18 });

// toRaw:獲取響應式物件的原始物件
let rawPerson = toRaw(person);

console.log(isReactive(person));
console.log(isReactive(rawPerson));

markRaw

標記一個物件,使其永遠不會變成響應式的

例如使用mockjs時,為了防止誤把mockjs變為響應式物件,可以使用 markRaw 去標記mockjs

let citys = markRaw([
  {id:'asdda01',name:'北京'},
  {id:'asdda02',name:'上海'},
  {id:'asdda03',name:'天津'},
  {id:'asdda04',name:'重慶'}
])
// 根據原始物件citys去建立響應式物件citys2 —— 建立失敗,因為citys被markRaw標記了,永遠不會**變成響應式的
let citys2 = reactive(citys)

customRef

建立一個自定義的ref,並對其依賴項跟蹤track和更新trigger觸發,進行邏輯控制

track():告訴Vue資料msg很重要,要對msg持續關注,一旦變化就更新
trigger():通知Vue資料msg變化了

<template>
  {{ msg }}
  <input type="text" v-model="msg" />
</template>

<script setup lang="ts">
let initValue = '哈哈哈';
import { customRef } from 'vue';
let msg = customRef((track, trigger) => {
  return {
    // get何時呼叫:msg被【讀取】的時候
    // set何時呼叫:msg被【修改】的時候

    get() {
      // track():告訴Vue資料msg很重要,要對msg持續關注,一旦變化就更新
      track();
      return initValue;
    },

    set(val) {
      initValue = val;
      // trigger():通知Vue資料msg變化了
      trigger();
    },
  };
});
</script>

新元件-Teleport

Teleport 是一種能夠將我們的元件html結構移動到指定位置的技術

import { Teleport } from 'vue';
// to 指定移動到的具體位置
<Teleport to='body' >
    <div class="modal" v-show="isShow">
      <h2>我是一個彈窗</h2>
      <p>我是彈窗中的一些內容</p>
      <button @click="isShow = false">關閉彈窗</button>
    </div>
</Teleport>

新元件-Suspense

等待非同步元件時渲染一些額外內容,讓應用有更好的使用者體驗

  • 非同步引入元件
  • 使用Suspense包裹元件,並配置好defaultfallback
<template>
    <div class="app">
        <h3>我是App元件</h3>
        <Suspense>
          <template v-slot:default>
            <Child/>
          </template>
          <template v-slot:fallback>
            <h3>載入中.......</h3>
          </template>
        </Suspense>
    </div>
</template>

import { defineAsyncComponent,Suspense } from "vue";
const Child = defineAsyncComponent(()=>import('./Child.vue'))

相關文章