# Vue3 toRef 和 toRefs 函式

ed。發表於2022-07-04

Vue3 toRef 和 toRefs 函式

上一篇博文介紹了 vue3 裡面的 ref 函式和 reactive 函式,實現響應式資料,今天主要來說一下 toRef 函式和 toRefs 函式的基本使用。

toRef 函式

通過上一篇部落格,我們知道,ref 函式可以建立一個響應式的資料,那 toRef 函式同樣也是建立一個響應式的資料,那麼他們之間的區別是什麼呢?

首先一點,ref 函式他的本質其實是去拷貝一份資料,脫離了與源資料的互動。什麼意思呢?就是 ref 函式可以將物件裡面的屬性值變成響應式的資料,修改響應式資料,是不會影響到源資料,但是檢視層上的資料會被更新。但是 toRefs 函式的本質是引用,也就是說,toRef 函式會與源資料互動,修改響應式資料會造成源資料的修改,但是他的修改不會造成檢視層資料的更新。

上面這段話理解嗎?不理解的話沒關係,下面通過幾個案例就可以明白了。

toRef 函式使用

首先呢, toRef 函式有兩個引數。

toRef(操作物件, 物件屬性)

好,接下來我們使用 toRef 函式寫一個案例,還是和以前一樣,頁面展示一個使用者的名稱和年紀。

<template>
  <div>
    <h1>toRef toRefs 函式</h1>
    <p>姓名:{{boy_toRef}}</p>
    <p>年齡:{{boy.age}}</p>
  </div>
</template>
<script>
  import { toRef } from 'vue'
  export default {
    setup() {
      const boy = {   // 建立一個使用者物件
        name: '我是??.',   // 使用者名稱稱
        age: 10    // 使用者年齡
      }
      // 使用 toRef 函式包裹,操作 boy 物件的 name 屬性
      const boy_toRef = toRef(boy, 'name')  
      console.log(boy_toRef)  // 我們直接列印看一下包裹後的資料格式
      return { boy, boy_toRef }
    }
  }
</script>

儲存程式碼,重新整理頁面。

在這裡插入圖片描述
我們可以看到資料的結構,在 value 裡面直接就是 boy 下面 name 的屬性值,所以說,接下來我們編寫一個按鈕,點選按鈕,修改這個 name 值。

<template>
  <div>
    <h1>toRef toRefs 函式</h1>
    <p>姓名:{{boy_toRef}}</p>
    <p>年齡:{{boy.age}}</p>
    <el-button type="primary" @click="btn">修改 name</el-button>
  </div>
</template>
<script>
  import { toRef } from 'vue'
  export default {
    setup() {
      const boy = {
        name: '我是??.',
        age: 10
      }
      // 這個 boy_toRef 就是被 toRef 函式操作過的 boy 的 name 值
      const boy_toRef = toRef(boy, 'name')  
      const btn = () => {
        boy_toRef.value = '??.'  // 把 name 修改成 ??.
        console.log(boy_toRef)   // 修改完成列印一下結果
      }
      return { boy, btn, boy_toRef }
    }
  }
</script>

儲存程式碼重新整理頁面,然後點選按鈕看一下頁面效果。

在這裡插入圖片描述

通過截圖展示的效果我們可以發現,boy_toRef 的值確實被修改了,但是呢,頁面並沒有改變,而且頁面也沒有出現錯誤。

這是什麼原因呢? 其實這不是 Bug 哈,在本篇博文開始就說過,toRef 函式會與源資料互動,修改響應式資料會造成源資料的修改,但是他的修改不會造成檢視層資料的更新,所以說,這就是 toRef 函式的功能。確實,檢視沒有資料更新我們通過上面的截圖看到了,但是源資料修改這個怎麼看呢?沒關係,在回答這個問題之前,我們首先得知道,什麼是源資料。

就像上面的程式碼:

const boy = {
  name: '我是??.',
  age: 10
}
const boy_toRef = toRef(boy, 'name')

toRef 函式將 boy 物件給包裹了起來,所以說,boy 物件就是源資料。

所以說,想知道源資料有沒有改變,在點選按鈕之後,列印一下 boy 物件,看一下 boy 有沒有被改變。

<template>
  <div>
    <h1>toRef toRefs 函式</h1>
    <p>姓名:{{boy_toRef}}</p>
    <p>年齡:{{boy.age}}</p>
    <el-button type="primary" @click="btn">修改 name</el-button>
  </div>
</template>
<script>
  import { toRef } from 'vue'
  export default {
    setup() {
      const boy = {
        name: '我是??.',
        age: 10
      }
      const boy_toRef = toRef(boy, 'name')  // 這個 boy_toRef 就是被 toRef 函式操作過的 boy 的 name 值
      const btn = () => {
        boy_toRef.value = '??.'  // 把 name 修改成 ??.
        console.log(boy_toRef)   // 修改完成列印一下結果
        console.log(boy)   // 修改完成列印一下boy結果
      }
      return { boy, btn, boy_toRef }
    }
  }
</script>

儲存程式碼,重新整理頁面,在點選按鈕修改 name 值,然後檢視一下控制檯列印的 boy 物件。

在這裡插入圖片描述
發現 boy 物件的 name 值已經從 我是??. 改為 ??.了,但是頁面依舊沒有更新。

記住了!

toRef 函式會與源資料互動,修改響應式資料會造成源資料的修改,但是他的修改不會造成檢視層資料的更新。

ref 函式驗證

ref 函式可以將物件裡面的屬性值變成響應式的資料,修改響應式資料,是不會影響到源資料,但是檢視層上的資料會被更新 這句話是正確的嘛?上一節我們沒測試,所以說在這裡我們也測試一下。

我們還是寫一個案例,頁面展示一個名稱,點選按鈕,修改頁面名稱。

<template>
  <div>
    <h1>ref reactive 函式</h1>
    <p>姓名:{{name_ref}}</p>
    <el-button type="primary" @click="btn">修改資訊</el-button>
  </div>
</template>
<script>
  import { ref } from 'vue'
  export default {
    setup() {
      const name = '我是??.'
      const name_ref = ref(name)
      const btn = () => {
        name_ref.value = '??.'
        console.log(name_ref)  // 列印一下被ref包裹的資料
        console.log(name)   // 列印一下源資料
      }
      return { name_ref, btn }
    }
  }
</script>

儲存程式碼,重新整理頁面,點選按鈕檢視頁面控制檯列印的結果,主要是看一下被 ref 函式包裹後的資料有沒有修改成功,源資料有沒有修改成功,最後頁面有沒有修改,下面看截圖。

在這裡插入圖片描述

OK,通過上面截圖,顧忌大家都理解了吧!

所以再記住!

ref 函式可以將物件裡面的屬性值變成響應式的資料,修改響應式資料,是不會影響到源資料,但是檢視層上的資料會被更新

toRefs 函式

toRefs 函式的使用呢,其實和 toRef 函式類似的哈。

  • toRefs 函式用於批量設定多個資料為相應是資料。
  • toRefs 函式與原始資料相互動,修改響應式資料會影響到源資料,但是不會更新檢視層。
  • toRefs 函式還可以與其他響應式資料相互動,更加方便處理檢視層資料。

toRefs 函式使用

老樣子,建立一個物件,然後使用 toRefs 函式包裹,在頁面展示一下。

<template>
  <div>
    <h1>toRef toRefs 函式</h1>
    <p>姓名:{{boy_toRefs.name}}</p>
    <p>年齡:{{boy_toRefs.age}}</p>
  </div>
</template>
<script>
  import { toRefs } from 'vue'
  export default {
    setup() {
      const boy = {
        name: '我是??.',
        age: 10
      }
      const boy_toRefs = toRefs(boy)   // 將 boy 用 toRefs 包裹
      console.log(boy_toRefs)   // 列印一下結果
      return { boy_toRefs }
    }
  }
</script>

儲存程式碼,重新整理頁面檢視。

在這裡插入圖片描述

所以說,我們修改修改一下程式碼,在渲染的時候除了 .屬性 之外,還需要 .value。

    <p>姓名:{{boy_toRefs.name.value}}</p>
    <p>年齡:{{boy_toRefs.age.value}}</p>

把檢視層程式碼修改一下,然後檢視效果。

在這裡插入圖片描述

誒,現在就是正常的啦!

有人可能會疑問,那這玩意兒整的不是越來越複雜了嗎?本來直接點屬性就可以,現在還得點屬性點value,不是多此一舉,脫褲子放P嗎? 嘿嘿嘿!我覺得也是。

為什麼呢說是多此一舉也很正常,因為前面的博文講過,這種複雜結構資料我們完全可以使用 reactive 函式來處理呀,渲染最多點一次就可以,但是 toRefs 函式卻需要點兩次。

<template>
  <div>
    <h1>toRef toRefs 函式</h1>
    <p>姓名:{{boy_toRefs.name}}</p>
    <p>年齡:{{boy_toRefs.age}}</p>
  </div>
</template>
<script>
  import { toRefs, reactive } from 'vue'
  export default {
    setup() {
      const boy = {
        name: '我是??.',
        age: 10
      }
      const boy_toRefs = reactive(boy)
      return { boy_toRefs }
    }
  }
</script>

我們不使用 toRefs 函式,而是用之前說的 reactive 函式處理資料。

在這裡插入圖片描述

我們可以看到,頁面是可以正常解析的,那為什麼我們還有捨近求遠的使用 toRefs 函式呢?

其實是有原因的呀!

其實 toRefs 函式最大的用處在這裡!

我們這個 boy 物件裡面只有兩個引數比較少,如果我們這個物件裡面有十個引數或者是更多的話,每次展示的時候都得寫那麼多遍的 boy 點,是不是很麻煩呢?所以說使用 toRefs 函式就可以解決這個問題,看下面的程式碼。

<template>
  <div>
    <h1>toRef toRefs 函式</h1>
    <p>姓名:{{name}}</p>
    <p>年齡:{{age}}</p>
  </div>
</template>
<script>
  import { toRefs } from 'vue'
  export default {
    setup() {
      const boy = {
        name: '我是??.',
        age: 10
      }
      return { boy_toRefs , ...toRefs(boy)}
    }
  }
</script>

在 return 丟擲 reactive 的時候,使用擴充套件運算子和 toRefs 函式,就可以實現直接寫屬性的方式展示資料了。

在這裡插入圖片描述
但是呢,深層次的物件依舊需要通過點來實現。

也許你還有疑問,直接擴充套件運算 reactive 函式也行啊,為啥要套上 toRefs 函式,記住一點呀!

toRefs 函式修改,原始資料被改變,頁面不會被觸發。

看下面程式碼:

<template>
  <div>
    <h1>toRef toRefs 函式</h1>
    <p>姓名:{{name}}</p>
    <p>年齡:{{age}}</p>
    <el-button type="primary" @click="btn">修改 name</el-button>
  </div>
</template>
<script>
  import { toRefs, reactive } from 'vue'
  export default {
    setup() {
      const boy = {
        name: '我是??.',
        age: 10
      }
      const new_toRefs = toRefs(boy)

      const btn = () => {
        new_toRefs.name.value = '??.'
        console.log(boy)
      }

      return { btn, ...toRefs(boy) }
    }
  }
</script>

列印一下結果:

在這裡插入圖片描述

從列印結果中可以看出,原始資料被改變,頁面沒有被觸發。但從我的寫法上應該可以注意到,toRefs 返回的物件,隨便解、隨便構,絲毫不會影響值的響應性。

總結

有的小夥伴可能還是不太理解這兩個函式,稍微總結一下子。

  • 如果想讓響應式資料和以前的資料關聯起來,並且想在更新響應式資料的時候不更新檢視,那麼就使用 toRef 函式。
  • 如果希望將物件的多個屬性都變成響應式資料,並且要求響應式資料和原始資料關聯,並且更新響應式資料的時候不更新檢視,就使用 toRefs 函式用於批量設定多個資料為響應式資料。因為 toRef 函式一次僅能設定一個資料。
  • toRefs 函式接收一個物件作為引數,它會遍歷物件身上的所有屬性,然後挨個呼叫 toRef 函式執行。

好了,今天的內容大體就是這些了,晚安寶子們,明天見!

相關文章