ref接受一个内部值,返回一个响应式的、可更改的 ref 对象,此对象只有一个指向其内部值的属性 .value
基本数据的响应式都是通过ref来创建。
一:refhook源码目录位置
packages -> reactivity -> src -> ref.ts
ref
- ref函数
export function ref(value?: unknown) {
return createRef(value)
}
- createRef
export function isRef<T>(r: Ref<T> | unknown): r is Ref<T>
export function isRef(r: any): r is Ref {
return Boolean(r && r.__v_isRef === true)
}
function createRef(rawValue: unknown, shallow = false) {
if (isRef(rawValue)) {
return rawValue
}
return new RefImpl(rawValue, shallow)
}
isRef判断传入的是不是一个ref对象,如果是就直接return出去。 ref对象会有个__v_isRef属性
RefImpl
- RefImpl类的实现
class RefImpl<T> {
private _value: T
public readonly __v_isRef = true
constructor(private _rawValue: T, private readonly _shallow = false) {
this._value = _shallow ? _rawValue : convert(_rawValue)
}
get value() {
track(toRaw(this), TrackOpTypes.GET, 'value')
return this._value
}
set value(newVal) {
if (hasChanged(toRaw(newVal), this._rawValue)) {
this._rawValue = newVal
this._value = this._shallow ? newVal : convert(newVal)
trigger(toRaw(this), TriggerOpTypes.SET, 'value', newVal)
}
}
}
- _rawValue:源数据
- _shallow: 一个布尔值,指示是否应该只进行浅层的响应式转换
constructor中执行
- convert函数
export const isObject = (val: unknown): val is Record<any, any> =>{
return val !== null && typeof val === 'object'
}
const convert = <T extends unknown>(val: T): T =>{
return isObject(val) ? reactive(val) : val
}
isObject函数在源码中的位置: packages -> reactivity -> src -> index.ts 如果传入的数据是对象的话,就走reactive创建响应式。基本数据类型就在RefImpl中做响应式处理
get value 解读
- toRaw 函数的目的是获取一个响应式对象背后的原始对象。如果传入的对象不是响应式的,那么直接返回该对象
export const enum ReactiveFlags {
SKIP = '__v_skip', // 标记一个对象或属性应该被Vue的响应式系统跳过。
IS_REACTIVE = '__v_isReactive', // 标记一个对象是否是响应式的。
IS_READONLY = '__v_isReadonly', // 标记一个对象是否是只读的
RAW = '__v_raw' // 用于存储响应式对象的原始版本。
}
export interface Target {
[ReactiveFlags.SKIP]?: boolean
[ReactiveFlags.IS_REACTIVE]?: boolean
[ReactiveFlags.IS_READONLY]?: boolean
[ReactiveFlags.RAW]?: any
}
export function toRaw<T>(observed: T): T {
return (
(
observed && toRaw((observed as Target)[ReactiveFlags.RAW])
)
|| observed)
}
track 函数用于追踪依赖关系的函数,以便在数据变化时能够自动通知并更新依赖于这些数据的副作用(effect)或观察者(watcher)
export function track(target: object, type: TrackOpTypes, key: unknown) {
if (!shouldTrack || activeEffect === undefined) {
return
}
let depsMap = targetMap.get(target)
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()))
}
let dep = depsMap.get(key)
if (!dep) {
depsMap.set(key, (dep = new Set()))
}
if (!dep.has(activeEffect)) {
dep.add(activeEffect)
activeEffect.deps.push(dep)
if (__DEV__ && activeEffect.options.onTrack) {
activeEffect.options.onTrack({
effect: activeEffect,
target,
type,
key
})
}
}
}
- shouldTrack 全局变量,用于是否以来追踪
- activeEffect 当前激活的effect
- targetMap 存储副作用函数的集合
这里就不对track函数做更多的解读,后面会在effect中做介绍
set value 解读
hasChanged函数, 比较一个值是否发生改变,考虑NAN的情况
// compare whether a value has changed, accounting for NaN.
export const hasChanged = (value: any, oldValue: any): boolean =>
value !== oldValue && (value === value || oldValue === oldValue)
如值发生改变的话,就去修改值,并且通知相关effect,触发响应