- Автор: Чен Даютоу
- гитхаб:KRISACHAN
как новая функцияComposition API,существуетVue3Он был выпущен за некоторое время до официального релиза.
Из введения документации,Composition APIпредставляет собой набор малонавязчивых, функциональных API, которые позволяют нам быть более гибкими».комбинация"логика компонента.
не только вVueв других фреймворках или нативныхJSЕго тоже можно очень хорошо использовать.Ниже мы выберем еще несколько важных.Composition API, на нескольких простых примерах, чтобы увидеть, как использовать его в других проектах.
Примечание. В этой статье перечислены только наиболее важные API в каждой категории. Если вы хотите просмотреть их все, вы можете щелкнуть ссылки ниже, чтобы просмотреть их:
reactive API
createReactiveObject
createReactiveObjectфункцияreactive APIЯдро для созданияreactiveобъект .
Прежде чем поделиться API, давайте взглянем на его основную реализацию. Из-за ограниченного места в этой статье показана только упрощенная версия кода после понимания, код выглядит следующим образом:
function createReactiveObject(
target, // 要监听目标
isReadonly, // 是否只读
baseHandlers, // target 为 Object 或 Array 时的处理器,支持对数据的增删改查
collectionHandlers // target 为 Map/WeakMap 或 Set/WeakSet 时的处理器,支持对数据的增删改查
) {
if (target[ReactiveFlags.RAW] && !(isReadonly && target[ReactiveFlags.IS_REACTIVE]) {
// 当 target 已经是一个 Proxy 时,直接返回
// 例外情况:在 Proxy 里调用 readonly()
return target
}
// 当前对象已被监听过时,就直接返回被监听的对象
if (existingProxy) {
return existingProxy
}
// 如果是 Object Array Map/WeakMap Set/WeakSet 以外只能监听到值的数据,直接返回
if (targetType === TargetType.INVALID) {
return target
}
// 根据参数类型生成对应的 Proxy 对象,以及添加对应的处理器
const proxy = new Proxy(
target,
targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers
)
proxyMap.set(target, proxy)
return proxy
}
reactive
Принимает простой объект и возвращает реактивный прокси для этого простого объекта. Эквивалент 2.x
Vue.observable()
Пример выглядит следующим образом:
import {
reactive,
isReactive // 判断是否是 reactive 对象
} from 'https://unpkg.com/@vue/reactivity/dist/reactivity.esm-browser.js'
const obj = {
nested: {
foo: 1
},
array: [{ bar: 2 }]
}
const value = 10
const observedObj = reactive(obj)
const observedValue = reactive(value)
console.log(isReactive(observedObj)) // true
console.log(isReactive(observedValue)) // true
shallowReactive
Создавайте поверхностный реактивный прокси только для частных (первого уровня) свойств объекта, не делайте глубокий рекурсивный реактивный прокси для «свойств свойства», а просто оставьте его как есть.
Пример выглядит следующим образом:
const obj = {
nested: {
foo: 1
},
array: [{ bar: 2 }]
}
const value = 10
const unobservedObj = shallowReactive(obj)
const unobservedValue = shallowReactive(value)
console.log(isReactive(observedObj)) // false
console.log(isReactive(observedValue)) // false
effect API
createReactiveEffect
createReactiveEffectЯвляется ли ядром API эффекта, используемый для создания заданных пользователем слушателейreactiveфункция объекта
Прежде чем поделиться API, давайте взглянем на его основную реализацию. Из-за ограниченного места в этой статье показана только упрощенная версия кода после понимания, код выглядит следующим образом:
function createReactiveEffect(
fn, // 用户创建的 reactive 对象变动执行回调
options = {
lazy, // 是否执行用户函数
scheduler, // 收集数据记录
onTrack, // 追踪用户数据的回调
onTrigger, // 追踪变更记录
onStop, // 停止执行
allowRecurse // 是否允许递归
}
) {
const effect = function reactiveEffect() {
if (!effectStack.includes(effect)) {
cleanup(effect) // 清空 effect
try {
enableTracking() // 往追踪用户数据的栈内添加当前 effect
effectStack.push(effect) // 往 effect 栈内添加 effect
activeEffect = effect // 将活动 effect 变成当前 effect
return fn() // 执行回调
} finally { // 删除当前记录
effectStack.pop()
resetTracking()
activeEffect = effectStack[effectStack.length - 1]
}
}
}
effect.id = uid++
effect._isEffect = true
effect.active = true
effect.raw = fn
effect.deps = []
effect.options = options
return effect
}
effect
effectфункцияeffect APIОсновной. кWeakMapЭто тип данных, который используется для хранения пользовательских функций.подписчик.
Пример выглядит следующим образом:
let dummy
const counter = reactive({ num: 0 })
effect(() => (dummy = counter.num))
console.log(dummy === 0) // true
counter.num = 7
console.log(dummy === 7) // true
ref API
RefImpl
RefImplэто ядро ref API, используемое для созданияrefобъект
Прежде чем поделиться API, давайте взглянем на его основную реализацию.Код выглядит следующим образом:
class RefImpl {
private _value // 存储当前 ref 对象的值
public __v_isRef = true // 确定是否为 ref 对象的变量 (只读)
constructor(
private _rawValue, // 用户传入的原始值
public readonly _shallow = false // 当前 ref 对象是否为 shallowRef
) {
// convert:如果传入的原始值为对象,则会被 convert 函数转换为 reactive 对象
this._value = _shallow ? _rawValue : convert(_rawValue)
}
get value() {
// 用于追踪用户输入的值变化
// track:effect api 的 track 函数,用于追踪用户行为,当前则是追踪用户的 get 操作
// toRaw:effect api 的 toRaw 函数,将 this 转化为用户输入值
track(toRaw(this), TrackOpTypes.GET, 'value')
return this._value
}
set value(newVal) {
if (hasChanged(toRaw(newVal), this._rawValue)) {
// 当前 ref 对象有变化时
// _rawValue / _value 变更
// trigger:effect api 的 trigger 函数,根据用户传入的值与操作类型来进行操作,当前则为将用户传入的值添加到值 map 里
this._rawValue = newVal
this._value = this._shallow ? newVal : convert(newVal)
trigger(toRaw(this), TriggerOpTypes.SET, 'value', newVal)
}
}
}
ref
Принимает значение параметра и возвращает реактивный и изменяемый объект ссылки. Объекты ref имеют одно свойство, указывающее на внутреннее значение
.value. Если переданная ссылка является объектом, она вызоветreactiveметод глубокой реактивной трансформации.
Пример выглядит следующим образом:
const count = ref({
name: '鱼头',
type: '帅哥'
})
console.log(count.value.type) // 帅哥
count.value.type = '超级大帅哥'
console.log(count.value.type) // 超级大帅哥
shallowRef
Создайте реф, который будет отслеживать его
.valueизменить операцию, но это не влияет на измененную.valueВыполняйте реактивные преобразования прокси (т. е. изменения не вызываютreactive)
Пример выглядит следующим образом:
const __shallowRef = shallowRef({ a: 1 })
let dummy
effect(() => {
dummy = __shallowRef.value.a
})
console.log(dummy) // 1
__shallowRef.value.a = 2
console.log(dummy) // 1
console.log(isReactive(__shallowRef.value)) // false
customRef
customRefдля пользовательскогоref, вы можете явно управлять отслеживанием зависимостей и триггерным ответом, принимать фабричную функцию, для отслеживания используются два параметраtrackИ используется для запуска ответаtriggerИ вернуть сgetа такжеsetсвойства объекта.
Пример выглядит следующим образом:
let value = 1
let _trigger
const custom = customRef((track, trigger) => ({
get() {
track()
return value
},
set(newValue) {
value = newValue
_trigger = trigger
}
}))
let dummy
effect(() => {
dummy = custom.value
})
console.log(dummy) // 1
custom.value = 2
console.log(dummy) // 1
_trigger()
console.log(dummy) // 2
triggerRef
triggerRefдля активного срабатыванияshallowRef
Пример выглядит следующим образом:
const __shallowRef = shallowRef({ a: 1 })
let dummy
effect(() => {
dummy = __shallowRef.value.a
})
console.log(dummy) // 1
__shallowRef.value.a = 2
console.log(dummy) // 1
console.log(isReactive(__shallowRef.value)) // false
triggerRef(__shallowRef)
console.log(dummy) // 2
computed API
ComputedRefImpl
ComputedRefImplэто ядро ref API, используемое для созданияcomputedобъект
Прежде чем поделиться API, давайте взглянем на его основную реализацию. Из-за ограниченного места в этой статье показана только упрощенная версия кода после понимания, код выглядит следующим образом:
class ComputedRefImpl {
private _value // 当前值
private _dirty = true // 当前值是否发生过变更
public effect // effect 对象
public __v_isRef = true; // 指定为 ref 对象
public [ReactiveFlags.IS_READONLY]: boolean // 是否只读
constructor(
getter, // getter
private _setter, // setter
isReadonly // 是否只读
) {
this.effect = effect(getter, {
lazy: true,
scheduler: () => {
if (!this._dirty) {
// 将变更状态变为 true
// trigger:effect api 的 trigger 函数,根据用户传入的值与操作类型来进行操作,当前则为将用户传入的值添加到值 map 里
this._dirty = true
trigger(toRaw(this), TriggerOpTypes.SET, 'value')
}
}
})
this[ReactiveFlags.IS_READONLY] = isReadonly
}
get value() {
if (this._dirty) {
// 返回当前值
// 将变更状态变为 false
this._value = this.effect()
this._dirty = false
}
// track:effect api 的 track 函数,用于追踪用户行为,当前则是追踪用户的 get 操作
track(toRaw(this), TrackOpTypes.GET, 'value')
return this._value
}
set value(newValue) {
this._setter(newValue)
}
}
computed
Передайте функцию получения, которая возвращает объект ref, который по умолчанию нельзя изменить вручную. или передать в собственность
getа такжеsetОбъект функции, которая создает изменяемое вручную состояние вычисления.
Пример выглядит следующим образом:
const count1 = ref(1)
const plus1 = computed(() => count1.value + 1)
console.log(plus1.value) // 2
plus1.value++ // Write operation failed: computed value is readonly
const count2 = ref(1)
const plus2 = computed({
get: () => count2.value + 1,
set: val => {
count2.value = val - 1
}
})
console.log(plus2.value) // 2
plus2.value = 0
console.log(plus2.value) // 0