VueUse
Shared ➜
computedEager
- watchEffect 的第二參數的
flush: sync
代表同步調用。 watchEffect
一直在檢查todo.length
,但因為result
是shallowRef
,所以只有在!!todo.length
的值發生改變時才會讓result
感受到變動並更新。
computedWithControl
- source 變動時
computedRef
可拿到新的 counter 值,否則都是舊的,若 source 沒有變動也可以透過computedRef.trigger()
去強制更新。 dirty
負責記錄是否被更新過(true
將重新取得 counter 的值)。- customRef 有兩個參數:
track
追蹤參數、trigger
觸發更新。 - Object.isExtensible() 判斷參數是否可以擴展 → 確認可以新增或修改 key / value。
createEventHook
- on 可以掛載多個 callback function,利用 trigger 觸發更新。
- tryOnScopeDispose() 判斷目前是否在 effect scope 內,是的話就執行
onScopeDispose()
,不是的話則什麼都不做。 - onScopeDispose() 在當前的 effect scope 上註冊一個處理 callback function,當相關的 effect scope 停止時會呼叫這個 callback function。
- Component 的 setup 或
scope.run()
的 function 裡面就代表是在 effect scope 裡面。
createGlobalState
- 建立一個獨立的 Scope,全域都可以存取同一份,像 Store。
- effect scope 的好處是若需要停止響應性可以直接
scope.stop()
,不需要一個一個做註銷(但這裡沒有提供此功能)
createInjectionState
和
createGlobalState
不同之處在於創建的狀態是在 Vue 的provide
/inject
系統中共享的,因此只有在注入到具有相同依賴的範圍內時才會共享。provide
/inject
可以明確地指定哪些變數是由哪些父層組件提供的,並限制這些變數的作用範圍,可以使程式碼更易於管理和理解,也可以減少不必要的全域變數。provide / inject 和全域共享的差別:
- 使用
provide
/inject
,子層要變更資料時必須透過父層提供的方法或資料屬性,然後讓父層透過provide
把變更後的資料傳遞下去,才能達到資料的共享。 - 使用全域變數,子層可以直接存取或修改全域變數,但因為沒有明確的資料流傳遞,所以可能會出現管理上的問題。
- 使用
composable()
可以組合多個響應式物件。在某些情況下,使用 composable 可以達到類似全域共享的效果,但是它們的本質是不同的。
- composable 主要是用於抽象出可重複使用的邏輯單元,這些邏輯單元可以在不同的 Vue 組件中使用,而不需要關注各自的狀態管理。(注重邏輯的抽象和可重複使用性)
- 全域共享主要是用於在整個應用中共享狀態,並且可以在任何組件中存取和修改這些狀態。(注重狀態的共享和可讀寫性)
createSharedComposable
- 和
createGlobalState
相似,差別在於createSharedComposable
在沒有任何訂閱使用的情況下會做scope.stop()
。 再次被使用才會重新創建 effectScope。
extendRef
- 可以對
ref
進行擴展,添加額外的 function 或屬性。 - 直接在
ref.value
上添加 function,可能會污染ref
的原型,進而影響到其他地方的使用,因此,使用extendRef
來對ref
進行擴展更加地優雅和安全。 unwrap
:若值為true
,則extendRef
函數將會將Ref
物件轉換為其值,並將其設置為屬性的值;false
的話屬性的值將是Ref
物件本身。if (key === 'value') continue
: 跳過extend
物件中key
為'value'
的屬性。 因為Ref
物件中的值是透過.value
存取的,如果直接將extend
物件中的value
屬性設置為Ref
物件的屬性會造成名稱衝突,因此需要跳過value
屬性。Object.defineProperty(ref, key, { get, set, enumerable })
:
會定義ref
物件的key
屬性的 getter 和 setter 方法,透過這些方法來操作Ref
物件的value
屬性(不需要.value
就能直接取到值)。Object.defineProperty(ref, key, { value, enumerable })
:
如果unwrap
被設定為false
,則直接將Ref
物件賦值給ref
物件的key
屬性,訪問ref.key
回傳的是Ref
物件本身(需要.value
才能取到值)。
get
unref()
:將參數轉換為普通的物件。MaybeRef<T>
:接受Ref
或普通值的參數。
使用MaybeRef<T>
作為類型註解的好處是,在接收參數時可以直接傳入普通值或Ref
。
isDefined
- 用於檢查變數是否已定義(defined)。
如果變數為null
或undefined
,該函數將回傳false
,否則回傳true
。
makeDestructurable
- 將物件和陣列組合起來,使其同時具有物件和陣列的特性,並且能夠進行解構操作。
typeof Symbol !== 'undefined’
:確認瀏覽器是否支援 Symbol 這個資料型別。- 在
obj
這個物件上,定義一個Symbol.iterator
屬性,並指定一個回傳迭代器物件的函式(陣列有此屬性,但物件沒有),當這個物件被迭代時,就會依次回傳arr
陣列中的值。 - 當程式碼使用
for...of
迴圈來迭代物件時,它會尋找該物件的Symbol.iterator
屬性,所以為了讓物件能夠被for...of
迴圈正確地迭代,需要為物件加上Symbol.iterator
屬性。 - 最後將
obj
和arr
合併成一個新的物件並回傳。
reactify
- 將普通的函数轉換為具有響應式特性的函數。
這些轉換後的函數可以接受 refs 作為參數,並回傳一個 ComputedRef 物件,可以訪問和監聽該物件的值的變化。 unref
:將 Ref 物件轉換為普通物件,如果傳入的參數不是 Ref 物件,則直接回傳該值。toValue
:傳入的參數是 function(getter)的話會執行,不是的話會做unref
。args.map(i => unrefFn(i))
:將所有參數map
成普通值。fn.apply(thisArg, [argsArray])
:fn
是要調用的函數,thisArg
是函數執行時的this
上下文,而argsArray
則是傳遞給函數的參數陣列。computed(() => fn.apply(this, args.map(i => unrefFn(i))))
:
將參數做轉為普通物件才能讓原本的fn
取到值並正常執行,而因為 computed 內部還是有用到unrefFn(i)
,對 computed 來說i
仍然會被搜集到響應性的依賴,所以當i
發生變化時,將會促使 computed 下次被取值時需要重新計算。
reactifyObject
- 如果屬性的值是一個函數,則使用 reactify 函數將其轉換為響應式函數。
Object.getOwnPropertyNames
:回傳一個陣列,其中包含物件自身所有屬性的名稱,包括不可列舉的屬性。Object.keys
:回傳一個陣列,其中僅包含物件自身的所有可列舉屬性的名稱。
reactiveComputed
- Computed reactive 物件。
回傳的是一個reactive
物件,而不是像computed
回傳的ref
物件。 (不需要.value
取值)
reactiveOmit
- 從一個響應式物件中響應式地省略字段。
javascript
import { reactive } from 'vue'
import { reactiveOmit } from '@vueuse/core'
const obj = reactive({
x: 0,
y: 0,
elementX: 0,
elementY: 0,
})
const picked = reactiveOmit(obj, "x", "elementX")
javascript
console.log(picked)
// Proxy {}
console.log(JSON.stringify(picked))
// {"y": 0, "elementY": 0}
console.log(picked.y)
// 0
console.log(obj)
// Proxy {x: 0, y: 0, elementX: 0, elementY: 0}
html
<div>
{{ picked }}
<!-- { "y": 0, "elementY": 0 } -->
</div>
Array.flat([depth])
:將一個多維陣列扁平化成新的一維陣列,參數可以指定展開的深度,預設為 1。Object.entries()
:直接取得所有屬性的 key 和 value,並以 Tuple 的陣列回傳。Object.fromEntries()
:將 key-value 的 Tuple 陣列轉換為物件。toRefs(reactiveObj)
:會將reactiveObj
轉換為一個物件,而物件內所有value
轉為ref
。ref
是響應式的,可以讓reactiveComputed
在需要時更新新物件的值。
reactivePick
- 從一個響應式物件中響應式地選擇字段。
UnwrapRef<T>
:對 Ref 型別做分解。 如果 T 是 Ref 型別,則 UnwrapRef 型別為 ref.value 的型別。 如果 T 不是 Ref 型別,則 UnwrapRef 型別為 T。- toRef():可用於將一個響應式物件(ref)的某個屬性轉換為一個獨立的響應式物件。
- 基本上與
reactiveOmit
相似,只是反過來。
refAutoReset
- 建立一個可透過參數指定時間(ms),並在時間到後重置為默認值的 ref。
refDebounced
- (Debounce)延遲更新 ref 值,在參數指定時間過後 ref 值的更新才會執行。
- 利用 useDebounceFn() 將更新值的動作延遲到指定時間結束後。
refDefault
- 給 ref 定義預設值(當
ref.value = undefined | null
時會get()
會取得預設值)。 - 回傳
computed
,將get()
內部做處理判斷。
refThrottled
- (Throttle)限制 ref 值的更新次數。
leading
:指定呼叫在 throttle 開始前。trailing
:指定呼叫在 throttle 結束後。
refWithControl
- 利用
extendRef
提供了兩個額外的函數get
和set
,以更好地控制何時 track / trigger 響應性。 - 不會觸發響應性的 getter
javascript
const foo = refWithControl('foo')
foo.get(false)
foo.untrackedGet()
foo.peek()
- 不會觸發響應性的 setter
javascript
const foo = refWithControl('foo')
foo.set('bar', false)
foo.silentSet('bar')
foo.lay('bar')
onBeforeChange()
:可以控制是否接受新的值。(拒絕就return false
)
javascript
const num = refWithControl(0, {
onBeforeChange(value, oldValue) {
if (Math.abs(value - oldValue) > 5)
return false
},
})
onChanged()
:與 Vue 的watch
相似,但它的同步開銷更少。
javascript
const num = refWithControl(0, {
onChanged(value, oldValue) {
console.log(value)
},
})
options.onBeforeChange?.(value, old)
先判斷onBeforeChange
是否為undefined | null
,若不是再進一步調用函數(和參數之間要加.
)。
resolveRef
- 將 value、ref 或 getter 規範化為
ref
或computed
。 - 判斷傳進的參數是否為 function,是的話回傳 computed,否則回傳 ref。
toValue
- 原本名稱是
resolveUnref
。 - 取得 value、ref、getter 的值。
- 判斷傳進的參數是否為 function(Getter),是的話回傳執行的結果,否則回傳
unref()
的結果。
set
ref.value = x
的簡寫。
javascript
set(ref, x) // ref
set(obj, key, x) // object
- 透過參數數量判斷要更新的值是 ref 或是 object。
syncRef
- 可以實現雙向引用(two-way refs)的同步,將兩個
Ref
物件之間的變更同步,也可以透過參數更改成單向同步。 - 回傳值是可以取消監聽器的函式。
- 使用
watch
而不是computed
的好處是有更多客製化的選項,包含:flush
、deep
、immediate
。
syncRefs
- 讓 target ref(多個可寫成陣列)的值與 source ref 的值保持同步。
- target 在傳入的時候若不是陣列(單個)會先另外放在陣列內,透過 forEach 將 source 的新值去賦值給每項
target.value
。 - 回傳值是可以取消監聽器的函式。
toReactive
- 將 ref 轉換為 reactive,還可以創建一個可替換的 reactive 物件。
toRefs
- 可以將普通或具響應性的物件、陣列等的最外層都轉換成 ref 以方便解構使用。
- 若傳入的參數不是 ref(普通的物件、陣列或 reactive),直接回傳 toRef() 的結果。
- 若傳入的參數是 ref,則不管是物件或是陣列都將最外層的每一項做
customRef()
。 - 每一項的
get()
和set()
都是從 objectRef 去取得或是藉由重新賦值去觸發 objectRef 的響應的。(也因此不需手動添加track()
和trigger()
)
tryOnBeforeMount
- 如果在 component 的生命週期內,呼叫
onBeforeMount
;不是則單純執行參數 function。 onBeforeMount
:負責處理在 component 初次渲染之前需要完成的操作。
調用的時機點為 component 已經完成設置其響應性狀態,但還沒有創建任何 DOM 節點,即將第一次地執行其 DOM 渲染效果。
tryOnBeforeUnmount
- 如果在 component 的生命週期內,呼叫
onBeforeUnmount
;不是則什麼都不做。 onBeforeUnmount
:調用時機為當 component instance 即將被卸載時(仍可使用)。
tryOnMounted
- 如果在 component 的生命週期內,呼叫
onMounted
;不是則單純執行參數 function。 onMounted
:調用時機為 component 被掛載後。
掛載的條件為
- 所有同步子元件都已經被掛載(不包括異步元件或在
<Suspense>
樹中的元件)。 - 自身的 DOM 樹已經被創建並插入到父容器中。(如果應用程式的根容器也在 document 中,則只保證元件的 DOM 樹在 document 中。)
tryOnScopeDispose
- 如果在 effect scope 內就執行
onScopeDispose()
,不是的話則什麼都不做。 onScopeDispose
:註冊一個 dispose callback 在當前的 effect scope 上,調用時機為相關的 effect scope 被停止時。
tryOnUnmounted
- 如果在 component 的生命週期內就執行
onUnmounted()
,不是的話則什麼都不做。 onUnmounted
:調用時機為 component 被卸載後。
卸載的條件為
- 所有子元件都被卸載。
- 所有相關的 reactive effects(渲染效果、在 setup 中所註冊的 computed 或 watchers)都被停止。
until
- 一次性的觀察變化(Promise)。
- function
toBe
的[v1, v2]
指的是r
和value
。
useArrayEvery
- 響應性的
Array.every
。 Array.every
的型別是
typescript
Array<T>.every(
predicate: (element: T, index: number, array: T[]) => unknown,
thisArg?: any
): boolean
所以傳入 useArrayEvery
的 fn
型別是 Array.every
的 predicate
型別。
- 在傳入
fn
參數時,是 callback function,不限制有幾項參數。 i
拿到的值為第一項(element
)。
useArrayFilter
- 響應性的
Array.filter
。
useArrayFind
- 響應性的
Array.find
。
useArrayFindIndex
- 響應性的
Array.findIndex
。
useArrayFindLast
- 響應性的
Array.findLast
。 !Array.prototype.findLast
:判斷版本是否有支援findLast
。
useArrayJoin
- 響應性的
Array.join
useArrayMap
- 響應性的
Array.map
useArrayReduce
- 響應式的
Array.reduce
。 MaybeRefOrGetter<MaybeRefOrGetter<T>[]>
代表MaybeRefOrGetter
的陣列裡每一項都是MaybeRefOrGetter
。type MaybeRefOrGetter<T> = MaybeReadonlyRef<T> | MaybeRef<T>
- Type
UseArrayReducer
是Array.reduce
第一個參數的型別:
typescript
(
previousValue: PV,
currentValue: CV,
currentIndex: number,
// array: T[]
) => R
useArraySome
- 響應式的
Array.some
。 - 如果直接寫
some(fn)
就不能將每次迭代的element
先做toValue
了。 fn(toValue(element), index, array)
應該會拿到原本該回傳的 boolean。
useArrayUnique
- 響應式的陣列且內部元素不重複。
- 若為物件陣列可以自定義判別式。
useCounter
- 附有功能的基本計數器。
useDateFormat
- 根據傳遞的令牌字符串(e.g.
YYYY-MM-DD
)獲取格式化的日期。 []
包起來的字串不會被解析成日期(因為:\[([^\]]+)]
)
可以拆成這樣看: \[ ( [^ \] ] + ) ]- 利用正則匹配和 replace 將字串轉換成日期。
!/Z$/i.test(date)
的用意是排除不需要做時區轉換的字串。(最後面如果是Z
就代表UTC +0
時區。)date.match(REGEX_PARSE)
將字串透過正則匹配回傳拆分完的陣列。
javascript
const REGEX_PARSE = /^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/
const date = '2000/11/23 15:23:38:34'.match(REGEX_PARSE)
// [ "2000/11/23 15:23:38:34", "2000", "11", "23", "15", "23", "38", "34" ]
str.substring(indexStart[, indexEnd])
回傳一個字串從indexStart
到indexEnd
前一項,或最後一項。
useDebounceFn
- (Debounce)延遲執行一個函數。
maxWait
:延遲的最大時間(ms),若都沒有達成調用則時限到必定調用一次。rejectOnCancel
:設置選項rejectOnCancel: true
才能catch
到 Promise 被拒絕。(決定lastRejector()
是執行resolve
還是reject
) 預設情況函數若被取消,Promise 不會被拒絕。createFilterWrapper()
會回傳一個回傳 Promise 的 function 。debounceFilter()
:
useInterval
- 響應性計數器(根據時間間隔增加)。
controls: exposeControls = false
將controls
取別名exposeControls
,預設為false
。
useIntervalFn
- 具控制功能的
setInterval
封裝程式。 - isClient:
typeof window !== 'undefined'
useLastChanged
- 記錄最後一次更改的時間戳。
- 內部以
watch
實作。
useThrottleFn
- 限制函數的執行。 對於限制處理程序在調整大小和滾動等事件上的執行速度特別有用。
trailing
:若為true
,將會在ms
時間結束後再次調用fn
。leading
:若為true
,則在ms
時間結束前一刻調用fn
。rejectOnCancel
:若為true
,如果已取消的話將拒絕最後一次呼叫。
useTimeout
- 控制在給定的時間後更新 value。
- 使用到
useTimeoutFn
,並回傳ready
表示是否完成更新。
useTimeoutFn
- 指定
cb
在interval
後再執行,計時時間內isPending = true
。
useToNumber
- 響應性地轉換字串 ref 為數字。
useToString
- 響應性地使用
${ }
將 ref 的 value 轉換成字串。
useToggle
- Boolean 切換器。
- 若參數傳進 ref,會回傳 toggle function。
- 為了預防
$event
擔任第一參數蓋掉 value,寫成useToggle()
以保證無參數傳入。 vue-demi
:為 Vue 2 和 Vue 3 所創建的通用函式庫。isRef
:檢查參數值是否為 ref 物件。
watchArray
- watch 陣列的添加和刪除。
- 類似 watch,但會將新增和移除的元素提供給 callback function。如果陣列透過
push
、splice
等方式作更新,將會傳遞{ deep: true }
。 type WatchSource<T = any> = Ref<T> | ComputedRef<T> | (() => T)
oldListRemains
:用來記錄陣列值的差異,false
表示這項值並不是新舊陣列都存在(可能是新增或是刪除了),true
則代表新舊陣列皆有(沒有變動)。found
:用來記錄是否為新增的值。false
代表舊陣列沒有這項值(需要新增到added
陣列和oldList
陣列內),true
則代表有(不需改動)。
watchAtMost
- 若觸發次數超過
count
,則會註銷 watch。 watchWithFilter()
回傳的stop
是註銷 watch 的函數。
watchDebounced
- 額外提供
debounce
和maxWait
的watch
。 - 基本就是使用
watchWithFilter
在參數eventFilter
傳入debounceFilter
。
watchIgnorable
- 回傳
ignoreUpdates(updater)
和ignorePrevAsyncUpdates()
以忽略對 source 的特定更新。 ignoreUpdates(updater)
:參數updater
(callback)對於 source 進行改動時不會觸發 watch。ignorePrevAsyncUpdates()
:只適用於非同步刷新pre
和post
。 如果使用了flush: 'sync'
,則ignorePrevAsyncUpdates()
不會起作用,因為每次更新 source 後,watch 將立即觸發。- 在
flush
為sync
的情況下,ignorePrevAsyncUpdates = () => {}
。 - source 每次更新時,
ignoreCounter
和syncCounter
會先歸零,接著syncCounter++
- 只有使用到
ignoreUpdates(updater)
或ignorePrevAsyncUpdates()
時ignoreCounter
才會> 0
。
watchImmediate
watch
的{ immediate: true }
版本。
watchOnce
- 只觸發一次的
watch
。 - 在執行指定函式時,利用
nextTick(() => stop())
去執行watch
所回傳的停止函式。
watchPausable
- 可以藉由回傳額外的
pause()
和resume()
函數來控制。 - 利用
watchWithFilter
再包一層判斷isActive
為true
才執行原函式的動作。 pause()
將isActive
設為false
,resume()
將isActive
設為True
。
watchThrottled
throttle
:在間隔期間內只允許調用一次。trailing
:在間隔期間內觸發,若為true
則會等待間隔時間結束後調用。若為false
則就算間隔時間結束也不會調用。leading
:若為true
則在觸發時立刻調用,若為false
則在間隔時間結束時才調用。- 基本就是使用
watchWithFilter
在參數eventFilter
傳入throttleFilter
。
watchTriggerable
- 提供在響應式物件沒有變動時也可以手動觸發 watch 的函式。
onCleanup
:會在下一次 watch 的 callback 函式執行前執行參數(也是 callback),可用來改變上一次 watch 的 callback 函式作用域內的變數。
watchWithFilter
- 回傳 watch,callback function 使用到
createFilterWrapper()
(可以多包一層需要的執行條件)。
whenever
- 參數格式與 watch 相同,差別在於是監測 Boolean 的響應式物件,當物件為
true
時才執行 callback。