Try   HackMD
tags: Vue

【Vue】響應式基礎 (Reactivity Fundamentals)

Document: https://vuejs.org/guide/essentials/reactivity-fundamentals.html

響應式物件 (Reactive objects)

能夠追蹤物件的存取權與狀態改變

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

SFC (Single-File Component) vs Codepen

option api
composition api

  1. 創建
  2. 使用
  3. 方法宣告

DOM 的更新時機

DOM 的更新是非同步的(不是你按下 Click Me 按鈕 DOM 就會馬上更新),使用 nextTick() 來確保 DOM 已經完全更新

深層響應

預設都是深層響應 (有淺層響應 shallowReactive)

【響應式 proxy】 與 【原始對象】

const raw = {} const proxy = reactive(raw) // proxy is NOT equal to the original. console.log(proxy === raw) // false console.log(proxy === reactive(raw)) // true

-> 要更改 proxy 才會具有響應式

reactive() 的限制

  • 只能作用在 object type (string、number、boolean 都不能作用)
  • 響應式系統是通過屬性追蹤
let state = reactive({ count: 0 }) state = reactive({ count: 1 })

更改區域變數、解構物件或是函數參數的值都不會影響原始的響應式物件

const state = reactive({ count: 0 }) let n = state.count // does not affect original state n++ let { count } = state // does not affect original state count++ callSomeFunction(state.count)

使用 ref()

import { ref } from 'vue' const count = ref(0)

ref() 會回傳一個 reactive 的物件( ref ),包含一個 value 屬性

ref 物件在模板中的展開( unwrapping )

你不用寫 .value

const count = ref(0); console.log(count); console.log(count.value);
  • 只會作用在最上層的物件
const object = { foo: ref(1) }
  • 不會動:
{{ object.foo + 1 }}

ref 物件在響應式物件中的展開

  • ref 物件如果被當成 reactive 物件的屬性,也會自己展開
const count = ref(0) const state = reactive({ count }) console.log(state.count) // 0 state.count = 1 console.log(count.value) // 1
  • ref 會取代 ref
const otherCount = ref(2) state.count = otherCount console.log(state.count) // 2 // original ref is now disconnected from state.count console.log(count.value) // 1
  • 只會作用在深層響應式物件

Arrays 與 Collections 的 ref 物件展開

  • array 與 collection 中不會自動展開(你要自己加上 .value)
const books = reactive([ref('Vue 3 Guide')]) // need .value here console.log(books[0].value) const map = reactive(new Map([['count', ref(0)]])) // need .value here console.log(map.get('count').value)

小結

  1. option api 中的 data 在 composition api 中 要使用 reactive() 或 ref() 來宣告
  2. reactive() 只能用在物件上
  3. ref 物件除了陣列與集合,其他都不需要用 .value

其他

option api 中的 debounce function

因為 Vue 的方法都是有狀態的 (stateful),在 Vue 中如果同時調用 debounce function component 之間就可能會互相影響

  • Stateful: 一個方法的計算結果會影響到其他程式碼就稱為 Stateful,反之稱為 Unstateful
  • debounce 是一種控制事件觸發頻率的方法,當一個事件被觸發時,它會延遲一段時間,如果在這段時間內有其他事件被觸發,則這個事件會被忽略掉。透過 debounce,可以控制事件的觸發頻率,防止事件被過度觸發。
import { debounce } from 'lodash-es' export default { methods: { // Debouncing with Lodash click: debounce(function () { // ... respond to click ... }, 500) } }

解決方法: 把 debounce 的創建移到 created 週期

export default { created() { // each instance now has its own copy of debounced handler this.debouncedClick = _.debounce(this.click, 500) }, unmounted() { // also a good idea to cancel the timer // when the component is removed this.debouncedClick.cancel() }, methods: { click() { // ... respond to click ... } } }

提問

  1. 什麼時候要用 ref(),什麼時候用 reactive()
  2. debounce ?

補充

Reactivity

Collection

pinia cheat sheet