ref( )
- 단일 값을 갖을 수 있다.
- 안타깝게도 Proxy는 객체에 대해서만 동작하므로 단일 값을 객체에 집어 넣어야 한다.
- 통상적인 Vue의 ref( )의 구현은 reactive( )를 활용하지 않고, 객체 접근자를 통해 구현되어 있다.
reactive( )를 활용한 구현
function ref(initialValue){
return reactive({value : initalValue});
}
객체 접근자를 활용한 구현
JavaScript Object 접근자
- JavaScript Object Accessors는 JavaScript computed 속성이라고도 한다.
- 주의!! Vue computed 속성과 혼동하지 말것!!
- (나의 생각) Java에서 객체를 생성하는 방식으로 getter, setter와 유사하며, json형태로 표기한 것
let user = {
firstName: 'Gregg',
lastName: 'Pollack',
get fullName() {
return '${this.firstName} ${this.lastName}'
},
set fullName(value) {
[this.firstName, this.lastName] = value.split(' ')
},
}
console.log(`Name is ${user.fullName}`);
user.fullName = 'Adam Jahr';
console.log(`Name is ${user.fullName}`);
구현 코드
const targetMap = new WeakMap() // targetMap stores the effects that each object should re-run when it's updated
let activeEffect = null // The active effect running
function track(target, key) {
if (activeEffect) {
// <------ Check to see if we have an activeEffect
// We need to make sure this effect is being tracked.
let depsMap = targetMap.get(target) // Get the current depsMap for this target
if (!depsMap) {
// There is no map.
targetMap.set(target, (depsMap = new Map())) // Create one
}
let dep = depsMap.get(key) // Get the current dependencies (effects) that need to be run when this is set
if (!dep) {
// There is no dependencies (effects)
depsMap.set(key, (dep = new Set())) // Create a new Set
}
dep.add(activeEffect) // Add effect to dependency map
}
}
function trigger(target, key) {
const depsMap = targetMap.get(target) // Does this object have any properties that have dependencies (effects)
if (!depsMap) {
return
}
let dep = depsMap.get(key) // If there are dependencies (effects) associated with this
if (dep) {
dep.forEach((effect) => {
// run them all
effect()
})
}
}
function reactive(target) {
const handler = {
get(target, key, receiver) {
let result = Reflect.get(target, key, receiver)
track(target, key) // If this reactive property (target) is GET inside then track the effect to rerun on SET
return result
},
set(target, key, value, receiver) {
let oldValue = target[key]
let result = Reflect.set(target, key, value, receiver)
if (result && oldValue != value) {
trigger(target, key) // If this reactive property (target) has effects to rerun on SET, trigger them.
}
return result
},
}
return new Proxy(target, handler)
}
function ref(raw) {
const r = {
get value() {
track(r, 'value')
return raw
},
set value(newVal) {
raw = newVal
trigger(r, 'value')
},
}
return r
}
// function ref(intialValue) {
// return reactive({ value: initialValue })
// }
function effect(eff) {
activeEffect = eff
activeEffect()
activeEffect = null
}
let product = reactive({ price: 5, quantity: 2 })
let salePrice = ref(0)
let total = 0
effect(() => {
salePrice.value = product.price * 0.9
})
effect(() => {
total = salePrice.value * product.quantity
})
console.log(
`Before updated quantity total (should be 9) = ${total} salePrice (should be 4.5) = ${salePrice.value}`
)
product.quantity = 3
console.log(
`After updated quantity total (should be 13.5) = ${total} salePrice (should be 4.5) = ${salePrice.value}`
)
product.price = 10
console.log(
`After updated price total (should be 27) = ${total} salePrice (should be 9) = ${salePrice.value}`
)
728x90
반응형
'FrameWorks > Vue' 카테고리의 다른 글
Vue의 watchEffect 와 watch 파헤치기 (0) | 2024.06.12 |
---|---|
Vue의 ModelValue 파헤치기 (0) | 2024.06.12 |
Vue의 nextTick() 파헤치기 (0) | 2024.06.12 |
Vue의 BaseHandler 파헤치기 (0) | 2024.06.12 |
reactive( ) (0) | 2023.07.11 |
댓글