iT邦幫忙

2023 iThome 鐵人賽

DAY 13
0
SideProject30

從零開始的firebase與Vue框架ーSNS專案系列 第 13

Day13—Vue(七)響應式基礎:ref和reactive的差別

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20230928/20162319Ewp14U310h.png

前言

前一篇文章介紹了模板語法,今天我們將介紹Vue3的響應式基礎。
在Vue3中,我們可以通過refreactive兩種響應式API創建響應式數據。refreactive都是非常重要的響應式編程方法,但是它們的適用場景和使用方式有一定的區別。在等等的文章即會討論到兩者的差異。

ref

Ref 可以持有任何类型的值,包括深层嵌套的对象、数组或者 JavaScript 内置的数据结构,比如 Map。
來源:官方文件

  • 接收一個值參數,返回一個可變的響應式數據源對象(RefImpl的實例對象)
  • 通過ref對象的.value屬性訪問或修改源值
  • 適用於使基本數據類型變為響應式,如字符串、數值等
  • 在js中操作數據時需要.value,讀取數據時在模板直接讀取不需要.value。

例一

<script>
import { ref } from "vue";
export default {
  setup() {
    let name = ref("小明");
    console.log(name);
    return {
      name
     
    };
  }
};
</script>

<template>
  <p>{{ name }}</p>
  <button @click="name = '小美'">換名字</button>
</template>

藉由console.logname我們可以明顯看出ref將接收對象變成一個RefImpl實例,且能透過.value屬性訪問對象值。

例二

<template>
  <div>{{count}}</div>
  <button @click='updateCount'>增加</button>
</template>

<script setup>
import { ref } from 'vue'

const count = ref(0)
console.log(count)

function updateCount() {
  count.value++
}
</script>


在這裡我們使用了script setup的方法,簡化程式碼並增加可閱讀性。

延伸資料:<script setup>與單元件組件(SFC)

為什麼要用ref不是用普通的變量?

Vue 的響應式系統是通過依賴追蹤實現的。當組件首次渲染時,Vue 會記錄模板中使用的所有 ref。之後當 ref 的值發生變化時,Vue 可以檢測到並觸發組件重新渲染。

在普通的 JavaScript 變量中,無法檢測到什麼時候變量被訪問或修改。但是對於對象的屬性,我們可以通過 getter 和 setter 方法來攔截它的讀寫操作。

ref 返回的就是一個擁有 getter 和 setter 的對象,其中 .value 屬性包含了實際的值。當我們訪問 .value 時會觸發 getter 進行依賴追蹤,當我們修改 .value 時會觸發 setter 進行響應式觸發。

簡單來說:使用 ref 是為了讓 Vue 能夠追蹤依賴、檢測變化並觸發響應。ref 對對象進行了包裝,使其支持響應式系統的工作機制。

该 .value 属性给予了 Vue 一个机会来检测 ref 何时被访问或修改。在其内部,Vue 在它的 getter 中执行追踪,在它的 setter 中执行触发。从概念上讲,你可以将 ref 看作是一个像这样的对象:
來源:官方文件

// 伪代码,不是真正的实现
const myRef = {
  _value: 0,
  get value() {
    track()
    return this._value
  },
  set value(newValue) {
    this._value = newValue
    trigger()
  }
}

reactive

  • 接收一個對象或數組,返回一個proxy代理對象
  • 響應式轉換是深層的,內部嵌套屬性也會變為響應式的
  • 直接訪問或修改代理對象的屬性,無需.value
  • 適用於創建響應式對象或數組
<template>
  <h3>姓名:{{user.name}}</h3>
  <h3>年齡:{{user.age}}</h3>
  <h3>wife:{{user.wife}}</h3>
  <button @click="updateUser">更新</button>
</template>


<script>
import { reactive } from "vue";
export default {
  setup() {
    const user = reactive({
      name: '大衛',
      age: 18,
      wife: {
        name: '珍妮',
        age: 18,
        books: ['罪與罰', '小王子', '龍與地下城'],
      },
    });
    const updateUser = () => {
      user.name = '琳達';
      user.age += 2;
      user.wife.books[0] = '論語';
    };
    console.log(user)
    return {
      user,
      updateUser,
    };
  },
};
</script>


reactive的響應式轉換是深層的,可以影響對象內部所有嵌套的屬性,使整個對象數據都變為響應式。這避免了層層包裝對象的麻煩。ref內部對對象的處理就是調用reactive進行響應式代理。ref需要訪問.value屬性是因為ref返回的是包裝對象,而reactive直接返回代理對象。

reactive看似很方便,但同時官方文件也指出了他的侷限性,並且推薦開發人員使用ref

  1. 有限的值类型:它只能用于对象类型 (对象、数组和如 Map、Set 这样的集合类型)。它不能持有如 string、number 或 boolean 这样的原始类型。

  2. 不能替换整个对象:

let state = reactive({ count: 0 })
// 上面的 ({ count: 0 }) 引用将不再被追踪
// (响应性连接已丢失!)
state = reactive({ count: 1 })
  1. 对解构操作不友好:当我们将响应式对象的原始类型属性解构为本地变量时,或者将该属性传递给函数时,我们将丢失响应性连接:
const state = reactive({ count: 0 })

// 当解构时,count 已经与 state.count 断开连接
let { count } = state
// 不会影响原始的 state
count++

// 该函数接收到的是一个普通的数字
// 并且无法追踪 state.count 的变化
// 我们必须传入整个对象以保持响应性
callSomeFunction(state.count)

來源:官方文件

總結

今天的文章就到這裡。ref適用於單值屬性,reactive適用於對象和數組。兩者可以配合使用,以實現響應式基礎。

參考資料

  1. 官方文件
  2. [Vue入門]リアクティビティの基礎

上一篇
Day12—Vue(六)模板語法(下):指令
下一篇
Day14—Vue(八)v-bind綁定class與style
系列文
從零開始的firebase與Vue框架ーSNS專案31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言