vue3 원본 학습 - 응답식reactive
73233 단어 vue3vue3 소스 분석reactive
문서 목록
가로막다
베이스
의 원리
어떻게 데이터의 변화를 감청합니까?
Proxy、Reflect function reactive(target) {
return new Proxy(target, handle)
}
const handle = {
get, set };
function get(target, propKey, receiver) {
// console.log('get');
// return target[propKey]
return Reflect.get(target, propKey, receiver)
}
function set(target, propKey, value, receiver) {
// console.log('set')
// return target[propKey] = value
return Reflect.set(target, propKey, value, receiver)
}
테스트let obj = reactive({
a:1});
console.log(obj.a)// get
obj.a = 2// set
대상이 proxy를 반복하는 것을 피하다
테스트 코드let obj = {
a: '111'
}
// , proxy
let rec1 = reactive(obj)
let rec2 = reactive(obj)
console.warn(rec1 == rec2)//false
수정//WeakMap key
// objectList proxy
const objectList = new WeakMap()//key: target, value: proxy
function reactive(target) {
let proxy = objectList.get(target);
// ,
if (proxy !== void 0) {
return proxy
}
proxy = new Proxy(target, handle)
objectList.set(target, proxy)
return proxy
}
...
수정 후 테스트console.warn(rec1 == rec2)//true
proxy 대상이 다시 proxy에 의해
테스트let rec1 = reactive(obj)
let rec2 = reactive(rec1)
console.log(rec1 == rec2) //false
수정// objectList proxy
const objectList = new WeakMap()//key: target, value: proxy
// proxyList proxy proxy
const proxyList = new WeakMap()//key: proxy, value: target
function reactive(target) {
let proxy = objectList.get(target);
// ,
if (proxy !== void 0) {
return proxy
}
// target proxy
if(proxyList.has(target)){
return target
}
proxy = new Proxy(target, handle)
objectList.set(target, proxy)
proxyList.set(proxy,target)
return proxy
}
...
수정 후 테스트console.warn(rec1 == rec2)//true
객체 중 객체
테스트let obj = {
a: '111',
b: [1, 2, 3],
c: {
d: {
e: '123'
}
}
}
let rec1 = reactive(obj)
rec1.a = 1;//set
rec1.b.push(4)//get
rec1.c.d.e='===='//get
세그먼트와 대상의 변경 사항이 set을 터치하지 않았습니다
수정function get(target, propKey, receiver) {
console.log('get')
let proxy = Reflect.get(target, propKey, receiver)
return isObject(proxy) ? reactive(proxy) : proxy;
// , ,
}
function isObject(val) {
return typeof val === 'object' && val !== null;
}
수정 후 테스트rec1.b.push(4)
// get [ get(obj,'b') ]
// get [ get(obj.b,'push') ]
// get [ get(obj.b,'length') ]
// set [ set(obj.b, 3) ]
// set [ set(obj.b,'length') ]
rec1.c.d.e='===='
// get
// get
// set
위 문서는 reactive.js
에 보관
모니터
데이터 변화 모니터링
데이터를 가져올 때 (get) 수집하려면 track 방법
데이터를 업데이트할 때 (set) 수집에서 페이지를 찾아서 업데이트해야 합니다. trigger 방법
감청 함수
우선 감청 함수를 써서 데이터가 변하면 이 방법을 실행합니다.
테스트 코드let obj = {
a: '111',
}
let rec1 = reactive(obj);
// effect : , ,
//
effect(()=>{
console.log(' ',rec1.a);
})
실행 과정:effect->fn->get->track,
트랙 시 fn 방법 수집
그러나track과effect는 두 가지 방법입니다.effect의fn은track에서targetMap
에 어떻게 저장합니까?
아이디어:effect
이 호출될 때 즉시 한 번 촉발(호출)됩니다.
터치할 때 fn을 임시 변수에 저장하고 트랙에서 꺼냅니다.
코드// reactive.js
function get(target, propKey, receiver) {
// console.log('get')
track(target, 'get', propKey)
return Reflect.get(target, propKey, receiver)
}
// effect.js
let targetMap = new WeakMap()// key:obj
//get
function track(target, type, key) {
console.log('track- ', type, target, key)
let depsMap = targetMap.get(target);
//targetMap target ,
if (depsMap === void 0) {
console.log(' depsMap')
targetMap.set(target, (depsMap = new Map()))
}
//depsMap key ,
let dep = depsMap.get(key)
if (dep === void 0) {
console.log(' key')
depsMap.set(key, (dep = new Set()))
}
//
if (!dep.has(effectFn)) {
console.log(' effect, effect')
dep.add(effectFn)
}
}
// effect fn
let effectFn = null;
function effect(fn){
effectFn=fn;
fn();
}
코드 실행 프로세스effect(()=>{
console.log(' 1',rec1.a)
})
effect(()=>{
console.log(' 2',rec1.a)
})
// : effect->fn->get->track
track , `effect fn` `targetMap`
targetMap:{
//WeakMap
key: {
a:'111'},//
value:{
//Map
key:'a',
value:{
0: ()=>{
console.log(' 1',rec1.a) }
1: ()=>{
console.log(' 2',rec1.a) }
// effect, 。
}//Set
}
}
문제.
effectFn 임시 변수는 트랙을 할 때 targetMap
에 넣으면 effectFn이 쓸모가 없기 때문에 비워야 합니다.
만약 비우지 않으면 발생하는 문제는 effect
후 get
시 get->track 시 effectFn
을 targetMap
의 b
의 104591410 에 넣는다//
let obj = {
a: '111',
b: 'bbb'
}
let rec1 = reactive(obj);
effect(() => {
console.log(' 1', rec1.a)
})
effect(() => {
console.log(' 2', rec1.a)
})
console.log(' get ', rec1.b)
그래서
function reactive(target) {
return new Proxy(target, handle)
}
const handle = {
get, set };
function get(target, propKey, receiver) {
// console.log('get');
// return target[propKey]
return Reflect.get(target, propKey, receiver)
}
function set(target, propKey, value, receiver) {
// console.log('set')
// return target[propKey] = value
return Reflect.set(target, propKey, value, receiver)
}
let obj = reactive({
a:1});
console.log(obj.a)// get
obj.a = 2// set
let obj = {
a: '111'
}
// , proxy
let rec1 = reactive(obj)
let rec2 = reactive(obj)
console.warn(rec1 == rec2)//false
//WeakMap key
// objectList proxy
const objectList = new WeakMap()//key: target, value: proxy
function reactive(target) {
let proxy = objectList.get(target);
// ,
if (proxy !== void 0) {
return proxy
}
proxy = new Proxy(target, handle)
objectList.set(target, proxy)
return proxy
}
...
console.warn(rec1 == rec2)//true
let rec1 = reactive(obj)
let rec2 = reactive(rec1)
console.log(rec1 == rec2) //false
// objectList proxy
const objectList = new WeakMap()//key: target, value: proxy
// proxyList proxy proxy
const proxyList = new WeakMap()//key: proxy, value: target
function reactive(target) {
let proxy = objectList.get(target);
// ,
if (proxy !== void 0) {
return proxy
}
// target proxy
if(proxyList.has(target)){
return target
}
proxy = new Proxy(target, handle)
objectList.set(target, proxy)
proxyList.set(proxy,target)
return proxy
}
...
console.warn(rec1 == rec2)//true
let obj = {
a: '111',
b: [1, 2, 3],
c: {
d: {
e: '123'
}
}
}
let rec1 = reactive(obj)
rec1.a = 1;//set
rec1.b.push(4)//get
rec1.c.d.e='===='//get
function get(target, propKey, receiver) {
console.log('get')
let proxy = Reflect.get(target, propKey, receiver)
return isObject(proxy) ? reactive(proxy) : proxy;
// , ,
}
function isObject(val) {
return typeof val === 'object' && val !== null;
}
rec1.b.push(4)
// get [ get(obj,'b') ]
// get [ get(obj.b,'push') ]
// get [ get(obj.b,'length') ]
// set [ set(obj.b, 3) ]
// set [ set(obj.b,'length') ]
rec1.c.d.e='===='
// get
// get
// set
데이터 변화 모니터링
데이터를 가져올 때 (get) 수집하려면 track 방법
데이터를 업데이트할 때 (set) 수집에서 페이지를 찾아서 업데이트해야 합니다. trigger 방법
감청 함수
우선 감청 함수를 써서 데이터가 변하면 이 방법을 실행합니다.
테스트 코드
let obj = {
a: '111',
}
let rec1 = reactive(obj);
// effect : , ,
//
effect(()=>{
console.log(' ',rec1.a);
})
실행 과정:effect->fn->get->track,
트랙 시 fn 방법 수집
그러나track과effect는 두 가지 방법입니다.effect의fn은track에서
targetMap
에 어떻게 저장합니까?아이디어:
effect
이 호출될 때 즉시 한 번 촉발(호출)됩니다.터치할 때 fn을 임시 변수에 저장하고 트랙에서 꺼냅니다.
코드
// reactive.js
function get(target, propKey, receiver) {
// console.log('get')
track(target, 'get', propKey)
return Reflect.get(target, propKey, receiver)
}
// effect.js
let targetMap = new WeakMap()// key:obj
//get
function track(target, type, key) {
console.log('track- ', type, target, key)
let depsMap = targetMap.get(target);
//targetMap target ,
if (depsMap === void 0) {
console.log(' depsMap')
targetMap.set(target, (depsMap = new Map()))
}
//depsMap key ,
let dep = depsMap.get(key)
if (dep === void 0) {
console.log(' key')
depsMap.set(key, (dep = new Set()))
}
//
if (!dep.has(effectFn)) {
console.log(' effect, effect')
dep.add(effectFn)
}
}
// effect fn
let effectFn = null;
function effect(fn){
effectFn=fn;
fn();
}
코드 실행 프로세스
effect(()=>{
console.log(' 1',rec1.a)
})
effect(()=>{
console.log(' 2',rec1.a)
})
// : effect->fn->get->track
track , `effect fn` `targetMap`
targetMap:{
//WeakMap
key: {
a:'111'},//
value:{
//Map
key:'a',
value:{
0: ()=>{
console.log(' 1',rec1.a) }
1: ()=>{
console.log(' 2',rec1.a) }
// effect, 。
}//Set
}
}
문제.
effectFn 임시 변수는 트랙을 할 때
targetMap
에 넣으면 effectFn이 쓸모가 없기 때문에 비워야 합니다.만약 비우지 않으면 발생하는 문제는
effect
후 get
시 get->track 시 effectFn
을 targetMap
의 b
의 104591410 에 넣는다//
let obj = {
a: '111',
b: 'bbb'
}
let rec1 = reactive(obj);
effect(() => {
console.log(' 1', rec1.a)
})
effect(() => {
console.log(' 2', rec1.a)
})
console.log(' get ', rec1.b)
그래서
effectFn
이 있었고 targetMap
을 통해 의존 관계를 맺었다.effectFn
function track(target, type, key) {
console.log('track- ', type, target, key)
if (effectFn) {
...
// effect
if (!dep.has(effectFn)) {
dep.add(effectFn)
effectFn = null//
}
}
}
//
// effectFn = null
//
function effect(fn) {
try {
effectFn = fn;
fn();
} finally {
effectFn = null;
}
}
##set 시 종속 방법을 트리거합니다.
테스트 코드
effect(()=>{
console.log(' ',rec1.a)
})
rec1.a='222';
코드
// reactive.js
function set(target, propKey, value, receiver) {
let proxy = Reflect.set(target, propKey, value, receiver)
trigger(target, 'set', propKey)//trigger set, , 。
return proxy
}
// effect.js
function trigger(target, type, key) {
console.log('trigger- ', type)
let depsMap = targetMap.get(target)
if (depsMap) {
let deps = depsMap.get(key)
if (deps) {
// key effect
deps.forEach(effect => {
effect()
})
}
}
}
완벽하다
그룹이 변할 때 set을 여러 번 터치합니다.
function set(target, propKey, value, receiver) {
const oldvalue = target[propKey];
let proxy = Reflect.set(target, propKey, value, receiver)
// ,trigger
if (!target.hasOwnProperty(propKey)) {
trigger(target, 'add', propKey)
} else if (oldvalue !== value) {
trigger(target, 'set', propKey)
}
return proxy
}
삭제
// reactive.js
function deleteProperty(target, propKey) {
console.log(' ')
let proxy = Reflect.deleteProperty(target, propKey)
trigger(target, 'delete', propKey)
return proxy
}
//effect.js
function trigger(target, type, key) {
console.log('trigger- ', type,key)
let depsMap = targetMap.get(target)
if (depsMap) {
let deps = depsMap.get(key)
if (deps) {
// key effect
deps.forEach(effect => {
effect()
})
//
if(type == 'delete'){
console.log('delete')
depsMap.delete(key)
}
}
}
}
전체 코드
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<h1> , h1>
<h2>h2>
<button onclick="change()">Click mebutton>
<script src="./reactive.js">script>
<script src="./effect.js">script>
<script>
//
let obj = {
a: '111',
b: 'bbb',
c: [1,2,3]
}
let rec1 = reactive(obj);
effect(() => {
document.getElementsByTagName('h2')[0].innerText = rec1.a
})
function change(){
console.log('change')
rec1.a = Math.random()
}
script>
body>
html>
// reactive.js
//WeakMap key
// objectList proxy
const objectList = new WeakMap()//key: target, value: proxy
// proxyList proxy proxy
const proxyList = new WeakMap()//key: proxy, value: target
function reactive(target) {
let proxy = objectList.get(target);
// ,
if (proxy !== void 0) {
return proxy
}
// target proxy
if (proxyList.has(target)) {
return target
}
// ,
if (!isObject(target)) {
return target
}
proxy = new Proxy(target, handle)
objectList.set(target, proxy)
proxyList.set(proxy, target)
return proxy;
}
const handle = {
get, set, deleteProperty };
function get(target, propKey, receiver) {
console.log('get')
let proxy = Reflect.get(target, propKey, receiver);
track(target, 'get', propKey)
return isObject(proxy) ? reactive(proxy) : proxy;
// , ,
}
function set(target, propKey, value, receiver) {
const oldvalue = target[propKey];
let proxy = Reflect.set(target, propKey, value, receiver)
// ,trigger
if (!target.hasOwnProperty(propKey)) {
trigger(target, 'add', propKey)
} else if (oldvalue !== value) {
trigger(target, 'set', propKey)
}
return proxy
}
function deleteProperty(target, propKey) {
console.log(' ')
let proxy = Reflect.deleteProperty(target, propKey)
trigger(target, 'delete', propKey)
return proxy
}
//
function isObject(val) {
return typeof val === 'object' && val !== null;
}
//effect.js
//
let targetMap = new WeakMap()// key:obj
//get
function track(target, type, key) {
console.log('track- ', type, target, key)
if (effectFn) {
let depsMap = targetMap.get(target);
//targetMap target ,
if (depsMap === void 0) {
console.log(' depsMap')
targetMap.set(target, (depsMap = new Map()))
}
//depsMap key ,
let dep = depsMap.get(key)
if (dep === void 0) {
console.log(' key')
depsMap.set(key, (dep = new Set()))
}
// effect
if (!dep.has(effectFn)) {
console.log(' effect, effect')
dep.add(effectFn)
}
}
}
//set
function trigger(target, type, key) {
console.log('trigger- ', type,key)
let depsMap = targetMap.get(target)
if (depsMap) {
let deps = depsMap.get(key)
if (deps) {
// key effect
deps.forEach(effect => {
effect()
})
//
if(type == 'delete'){
console.log('delete')
depsMap.delete(key)
}
}
}
}
// effect fn
let effectFn = null;
function effect(fn) {
try {
console.log('try')
effectFn = fn;
fn();
} finally {
console.log('finally')
effectFn = null;
}
}
vue3 원본 학습 - 컴퓨터
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
내 새 책,오픈 소스 관리 시스템, vue-bag-admin
vue-bag-admin,use Vue3+Vite2.6+TypeScript+ant-design-vue,Provide the basic framework, quickly build enterprise-level bac...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<h1> , h1>
<h2>h2>
<button onclick="change()">Click mebutton>
<script src="./reactive.js">script>
<script src="./effect.js">script>
<script>
//
let obj = {
a: '111',
b: 'bbb',
c: [1,2,3]
}
let rec1 = reactive(obj);
effect(() => {
document.getElementsByTagName('h2')[0].innerText = rec1.a
})
function change(){
console.log('change')
rec1.a = Math.random()
}
script>
body>
html>
// reactive.js
//WeakMap key
// objectList proxy
const objectList = new WeakMap()//key: target, value: proxy
// proxyList proxy proxy
const proxyList = new WeakMap()//key: proxy, value: target
function reactive(target) {
let proxy = objectList.get(target);
// ,
if (proxy !== void 0) {
return proxy
}
// target proxy
if (proxyList.has(target)) {
return target
}
// ,
if (!isObject(target)) {
return target
}
proxy = new Proxy(target, handle)
objectList.set(target, proxy)
proxyList.set(proxy, target)
return proxy;
}
const handle = {
get, set, deleteProperty };
function get(target, propKey, receiver) {
console.log('get')
let proxy = Reflect.get(target, propKey, receiver);
track(target, 'get', propKey)
return isObject(proxy) ? reactive(proxy) : proxy;
// , ,
}
function set(target, propKey, value, receiver) {
const oldvalue = target[propKey];
let proxy = Reflect.set(target, propKey, value, receiver)
// ,trigger
if (!target.hasOwnProperty(propKey)) {
trigger(target, 'add', propKey)
} else if (oldvalue !== value) {
trigger(target, 'set', propKey)
}
return proxy
}
function deleteProperty(target, propKey) {
console.log(' ')
let proxy = Reflect.deleteProperty(target, propKey)
trigger(target, 'delete', propKey)
return proxy
}
//
function isObject(val) {
return typeof val === 'object' && val !== null;
}
//effect.js
//
let targetMap = new WeakMap()// key:obj
//get
function track(target, type, key) {
console.log('track- ', type, target, key)
if (effectFn) {
let depsMap = targetMap.get(target);
//targetMap target ,
if (depsMap === void 0) {
console.log(' depsMap')
targetMap.set(target, (depsMap = new Map()))
}
//depsMap key ,
let dep = depsMap.get(key)
if (dep === void 0) {
console.log(' key')
depsMap.set(key, (dep = new Set()))
}
// effect
if (!dep.has(effectFn)) {
console.log(' effect, effect')
dep.add(effectFn)
}
}
}
//set
function trigger(target, type, key) {
console.log('trigger- ', type,key)
let depsMap = targetMap.get(target)
if (depsMap) {
let deps = depsMap.get(key)
if (deps) {
// key effect
deps.forEach(effect => {
effect()
})
//
if(type == 'delete'){
console.log('delete')
depsMap.delete(key)
}
}
}
}
// effect fn
let effectFn = null;
function effect(fn) {
try {
console.log('try')
effectFn = fn;
fn();
} finally {
console.log('finally')
effectFn = null;
}
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
내 새 책,오픈 소스 관리 시스템, vue-bag-adminvue-bag-admin,use Vue3+Vite2.6+TypeScript+ant-design-vue,Provide the basic framework, quickly build enterprise-level bac...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.