1. 程式人生 > 其它 >Vue3.0系列(Composition API 的補充)

Vue3.0系列(Composition API 的補充)

技術標籤:vue3.0vue

上一篇我們說了ref 和 reactive建立資料,下面來做一些補充

1…遞迴監聽和非遞迴監聽

1.1 遞迴監聽

1. 預設情況下, 無論是通過ref還是reactive都是遞迴監聽
每一層都監聽

<template>
  <div>
      <p>{{state.a}}</p>
      <p>{{state.gf.b}}</p>
      <p>{{state.gf.f.c}}</p>
      <p>{{state.gf.f.s.d}}</p>
    <button @click="myFn">按鈕</button>
  </div>
</template>

<script>

import {reactive} from 'vue';
  // import {ref} from 'vue';
export default {
  name: 'App',
  setup() {
    let state = reactive({
        a:'a',
        gf:{
            b:'b',
            f:{
                c:'c',
                s:{
                    d:'d'
                }
            }
        }
    });
    function myFn() {
        state.a = '1';
        state.gf.b = '2';
        state.gf.f.c = '3';
        state.gf.f.s.d = '4';
        
        console.log(state);
        console.log(state.gf);
        console.log(state.gf.f);
        console.log(state.gf.f.s);
    }
    return {state, myFn}
  }
}
</script>

2.遞迴監聽存在的問題
如果資料量比較大, 非常消耗效能

列印後,發現每一層物件都被包裝為了Proxy物件,
如果資料量比較大, 非常消耗效能
在這裡插入圖片描述

2.2 非遞迴監聽

使用shallowReactiveshallowRef

shallowReactive:

<script>
 // 3.非遞迴監聽
import {shallowReactive} from 'vue';

export default {
  name: 'App',
  setup() {
    let state = shallowReactive({
    // let state = ref({
        a:'a',
        gf:{
            b:'b',
            f:{
                c:'c',
                s:{
                    d:'d'
                }
            }
        }
    });
    function myFn() {
        state.a = '1';
        state.gf.b = '2';
        state.gf.f.c = '3';
        state.gf.f.s.d = '4';
        console.log(state);
        console.log(state.gf);
        console.log(state.gf.f);
        console.log(state.gf.f.s);
    }
    return {state, myFn}
  }
}
</script>

再次列印輸出結果,發現只有第一層被封裝為了Proxy物件
但是第2, 3,4層資料為什麼也發生了變化呢?
因為修改了第一層,它就去修改UI了
在這裡插入圖片描述
shallowRef:

注意點:

  • 如果是通過shallowRef建立資料,
    那麼Vue監聽的是.value的變化, 並不是第一層的變化
  • Vue3只提供了triggerRef方法, 沒有提供triggerReactive方法
  • 所以如果是reactive型別的資料, 是無法主動觸發介面更新的
    triggerRef(state);

2.toRow 和 markRow

2.1 toRow

  • 從Reactive 或 Ref中得到原始資料
    let obj = {name:‘lnj’, age:18};
    let state = reactive(obj);
    let obj2 = toRaw(state);
  • toRaw作用 :做一些不想被監聽的事情(提升效能)

例子:
ref/reactive資料型別的特點:

  1. 每次修改都會被追蹤, 都會更新UI介面, 但是這樣其實是非常消耗效能的
  2. 所以如果我們有一些操作不需要追蹤, 不需要更新UI介面, 那麼這個時候,
  3. 我們就可以通過toRaw方法拿到它的原始資料, 對原始資料進行修改, 這樣就不會被追蹤, 這樣就不會更新UI介面, 這樣效能就好了
import {reactive, toRaw} from 'vue';
export default {
  name: 'App',
  setup() {
      let obj = {name:'lnj', age:18};
      // state和obj的關係:
      // 引用關係, state的本質是一個Proxy物件, 在這個Proxy物件中引用了obj
      let state = reactive(obj);
      let obj2 = toRaw(state);
 
      function myFn() {
          // 如果直接修改obj, 那麼是無法觸發介面更新的
          // 只有通過包裝之後的物件來修改, 才會觸發介面的更新
          obj2.name = 'zs';
          console.log(obj2); // {name: "zs", age: 18}
          console.log(state); // {name: "zs", age: 18}
      }
    return {state, myFn}
  }
}

上面的例子是,toRow獲取 Reactive型別的原始資料,
如果toRow要獲取 ref型別的原始資料,

注意點:

  • ref本質: reactive
    ref(obj) -> reactive({value: obj})
  • 注意點: 如果想通過toRaw拿到ref型別的原始資料(建立時傳入的那個資料)
    那麼就必須明確的告訴toRaw方法, 要獲取的是.value的值
    因為經過Vue處理之後, .value中儲存的才是當初建立時傳入的那個原始資料
  let obj = {name:'lnj', age:18};
  let state = ref(obj);
  let obj2 = toRaw(state.value);

2.2 markRow

markRaw
資料標記為永遠不能追蹤的資料
一般在編寫自己的第三方庫時使用

import {reactive, markRaw} from 'vue';
export default {
  name: 'App',
  setup() {
      let obj = {name: 'lnj', age: 18};
      obj = markRaw(obj);
      let state = reactive(obj);
      function myFn() {
          state.name = 'zs';
      }
    return {state, myFn}
  }
}

3. toRef 和 toRefs

  • toRef
    建立一個ref型別資料, 並和以前的資料關聯
  • toRefs
    批量建立ref型別資料, 並和以前資料關聯
  • toRef和ref區別
    ref創建出來的資料和以前無關(複製)
    toRef-創建出來的資料和以前的有關(引用)
    ref-資料變化會自動更新介面
    toRef-資料變化不會自動更新介面
<script>
  import {ref, toRef} from 'vue';
export default {
  name: 'App',
  setup() {
      let obj = {name:'lnj'};
      /*
      ref(obj.name) -> ref(lnj)
      -> reactive({value:lnj})
      * */
      // ref->複製
      // let state = ref(obj.name);
      // toRef->引用
      /*
      ref和toRef區別:
      ref->複製, 修改響應式資料不會影響以前的資料
      toRef->引用, 修改響應式資料會影響以前的資料
      ref->資料發生改變, 介面就會自動更新
      toRef->資料發生改變, 介面也不會自動更新

      toRef應用場景:
      如果想讓響應式資料和以前的資料關聯起來, 並且更新響應式資料之後還不想更新UI, 那麼就可以使用toRef
      * */
      let state = toRef(obj, 'name');

      function myFn() {
          state.value = 'zs';
          console.log(obj);
          console.log(state);
      }
    return {state, myFn}
  }
}
</script>