In previous versions of Vue we needed abstracted patterns like Higher Order Components (HOC), mixins or props to implement reactivity. The new functional API gives us the ability to encapsulate and reuse logic across multiple components without those abstracted patterns.
3. What is reactivity?
So reactivity or reactive programming is a declarative
programming paradigm concerned with data streams and the
propagation of change.
3
17. // data
const data = { x: 3, y: 6 };
// real data and deps behind
let realX = data.x;
let realY = data.y;
const realDepsX = [];
const realDepsY = [];
// track and trigger a property
const trackX = () => {
if (isDryRun && currentDep) {
realDepsX.push(currentDep);
}
};
const triggerX = () => {
realDepsX.forEach((dep) => dep());
};
const trackY = () => {
if (isDryRun && currentDep) {
realDepsY.push(currentDep);
}
};
const triggerY = () => {
realDepsY.forEach((dep) => dep());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const data = { x: 3, y: 6 };
// data1
2
3
// real data and deps behind4
let realX = data.x;5
let realY = data.y;6
const realDepsX = [];7
const realDepsY = [];8
9
// track and trigger a property10
const trackX = () => {11
if (isDryRun && currentDep) {12
realDepsX.push(currentDep);13
}14
};15
const triggerX = () => {16
realDepsX.forEach((dep) => dep());17
};18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
let realX = data.x;
let realY = data.y;
// data1
const data = { x: 3, y: 6 };2
3
// real data and deps behind4
5
6
const realDepsX = [];7
const realDepsY = [];8
9
// track and trigger a property10
const trackX = () => {11
if (isDryRun && currentDep) {12
realDepsX.push(currentDep);13
}14
};15
const triggerX = () => {16
realDepsX.forEach((dep) => dep());17
};18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
const realDepsX = [];
const realDepsY = [];
// data1
const data = { x: 3, y: 6 };2
3
// real data and deps behind4
let realX = data.x;5
let realY = data.y;6
7
8
9
// track and trigger a property10
const trackX = () => {11
if (isDryRun && currentDep) {12
realDepsX.push(currentDep);13
}14
};15
const triggerX = () => {16
realDepsX.forEach((dep) => dep());17
};18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
const trackX = () => {
if (isDryRun && currentDep) {
realDepsX.push(currentDep);
}
};
// data1
const data = { x: 3, y: 6 };2
3
// real data and deps behind4
let realX = data.x;5
let realY = data.y;6
const realDepsX = [];7
const realDepsY = [];8
9
// track and trigger a property10
11
12
13
14
15
const triggerX = () => {16
realDepsX.forEach((dep) => dep());17
};18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
const triggerX = () => {
realDepsX.forEach((dep) => dep());
};
// data1
const data = { x: 3, y: 6 };2
3
// real data and deps behind4
let realX = data.x;5
let realY = data.y;6
const realDepsX = [];7
const realDepsY = [];8
9
// track and trigger a property10
const trackX = () => {11
if (isDryRun && currentDep) {12
realDepsX.push(currentDep);13
}14
};15
16
17
18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
// data1
const data = { x: 3, y: 6 };2
3
// real data and deps behind4
let realX = data.x;5
let realY = data.y;6
const realDepsX = [];7
const realDepsY = [];8
9
// track and trigger a property10
const trackX = () => {11
if (isDryRun && currentDep) {12
realDepsX.push(currentDep);13
}14
};15
const triggerX = () => {16
realDepsX.forEach((dep) => dep());17
};18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
const watch = (fn) => {
isDryRun = true;
currentDep = fn;
fn();
currentDep = null;
isDryRun = false;
};
return realY;45
},46
set(v) {47
realY = v;48
triggerY();49
},50
});51
52
// watch a function53
let isDryRun = false;54
let currentDep = null;55
56
57
58
59
60
61
62
63
// define 3 functions64
const depA = () => console.log(`x = ${data.x}`);65
const depB = () => console.log(`y = ${data.y}`);66
const depC = () => console.log(`x + y = ${data.x + data.y}`);67
68
// dry-run all dependents69
watch(depA);70
watch(depB);71
9
18. // data
const data = { x: 3, y: 6 };
// real data and deps behind
let realX = data.x;
let realY = data.y;
const realDepsX = [];
const realDepsY = [];
// track and trigger a property
const trackX = () => {
if (isDryRun && currentDep) {
realDepsX.push(currentDep);
}
};
const triggerX = () => {
realDepsX.forEach((dep) => dep());
};
const trackY = () => {
if (isDryRun && currentDep) {
realDepsY.push(currentDep);
}
};
const triggerY = () => {
realDepsY.forEach((dep) => dep());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const data = { x: 3, y: 6 };
// data1
2
3
// real data and deps behind4
let realX = data.x;5
let realY = data.y;6
const realDepsX = [];7
const realDepsY = [];8
9
// track and trigger a property10
const trackX = () => {11
if (isDryRun && currentDep) {12
realDepsX.push(currentDep);13
}14
};15
const triggerX = () => {16
realDepsX.forEach((dep) => dep());17
};18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
let realX = data.x;
let realY = data.y;
// data1
const data = { x: 3, y: 6 };2
3
// real data and deps behind4
5
6
const realDepsX = [];7
const realDepsY = [];8
9
// track and trigger a property10
const trackX = () => {11
if (isDryRun && currentDep) {12
realDepsX.push(currentDep);13
}14
};15
const triggerX = () => {16
realDepsX.forEach((dep) => dep());17
};18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
const realDepsX = [];
const realDepsY = [];
// data1
const data = { x: 3, y: 6 };2
3
// real data and deps behind4
let realX = data.x;5
let realY = data.y;6
7
8
9
// track and trigger a property10
const trackX = () => {11
if (isDryRun && currentDep) {12
realDepsX.push(currentDep);13
}14
};15
const triggerX = () => {16
realDepsX.forEach((dep) => dep());17
};18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
const trackX = () => {
if (isDryRun && currentDep) {
realDepsX.push(currentDep);
}
};
// data1
const data = { x: 3, y: 6 };2
3
// real data and deps behind4
let realX = data.x;5
let realY = data.y;6
const realDepsX = [];7
const realDepsY = [];8
9
// track and trigger a property10
11
12
13
14
15
const triggerX = () => {16
realDepsX.forEach((dep) => dep());17
};18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
const triggerX = () => {
realDepsX.forEach((dep) => dep());
};
// data1
const data = { x: 3, y: 6 };2
3
// real data and deps behind4
let realX = data.x;5
let realY = data.y;6
const realDepsX = [];7
const realDepsY = [];8
9
// track and trigger a property10
const trackX = () => {11
if (isDryRun && currentDep) {12
realDepsX.push(currentDep);13
}14
};15
16
17
18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
// data1
const data = { x: 3, y: 6 };2
3
// real data and deps behind4
let realX = data.x;5
let realY = data.y;6
const realDepsX = [];7
const realDepsY = [];8
9
// track and trigger a property10
const trackX = () => {11
if (isDryRun && currentDep) {12
realDepsX.push(currentDep);13
}14
};15
const triggerX = () => {16
realDepsX.forEach((dep) => dep());17
};18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
// data1
const data = { x: 3, y: 6 };2
3
// real data and deps behind4
let realX = data.x;5
let realY = data.y;6
const realDepsX = [];7
const realDepsY = [];8
9
// track and trigger a property10
const trackX = () => {11
if (isDryRun && currentDep) {12
realDepsX.push(currentDep);13
}14
};15
const triggerX = () => {16
realDepsX.forEach((dep) => dep());17
};18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
const depA = () => console.log(`x = ${data.x}`);
const depB = () => console.log(`y = ${data.y}`);
const depC = () => console.log(`x + y = ${data.x + data.y}`);
52
// watch a function53
let isDryRun = false;54
let currentDep = null;55
const watch = (fn) => {56
isDryRun = true;57
currentDep = fn;58
fn();59
currentDep = null;60
isDryRun = false;61
};62
63
// define 3 functions64
65
66
67
68
// dry-run all dependents69
watch(depA);70
watch(depB);71
watch(depC);72
// output: x = 3, y = 6, x + y = 973
74
75
// mutate data76
data.x = 6;77
// 6 128
9
19. // data
const data = { x: 3, y: 6 };
// real data and deps behind
let realX = data.x;
let realY = data.y;
const realDepsX = [];
const realDepsY = [];
// track and trigger a property
const trackX = () => {
if (isDryRun && currentDep) {
realDepsX.push(currentDep);
}
};
const triggerX = () => {
realDepsX.forEach((dep) => dep());
};
const trackY = () => {
if (isDryRun && currentDep) {
realDepsY.push(currentDep);
}
};
const triggerY = () => {
realDepsY.forEach((dep) => dep());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const data = { x: 3, y: 6 };
// data1
2
3
// real data and deps behind4
let realX = data.x;5
let realY = data.y;6
const realDepsX = [];7
const realDepsY = [];8
9
// track and trigger a property10
const trackX = () => {11
if (isDryRun && currentDep) {12
realDepsX.push(currentDep);13
}14
};15
const triggerX = () => {16
realDepsX.forEach((dep) => dep());17
};18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
let realX = data.x;
let realY = data.y;
// data1
const data = { x: 3, y: 6 };2
3
// real data and deps behind4
5
6
const realDepsX = [];7
const realDepsY = [];8
9
// track and trigger a property10
const trackX = () => {11
if (isDryRun && currentDep) {12
realDepsX.push(currentDep);13
}14
};15
const triggerX = () => {16
realDepsX.forEach((dep) => dep());17
};18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
const realDepsX = [];
const realDepsY = [];
// data1
const data = { x: 3, y: 6 };2
3
// real data and deps behind4
let realX = data.x;5
let realY = data.y;6
7
8
9
// track and trigger a property10
const trackX = () => {11
if (isDryRun && currentDep) {12
realDepsX.push(currentDep);13
}14
};15
const triggerX = () => {16
realDepsX.forEach((dep) => dep());17
};18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
const trackX = () => {
if (isDryRun && currentDep) {
realDepsX.push(currentDep);
}
};
// data1
const data = { x: 3, y: 6 };2
3
// real data and deps behind4
let realX = data.x;5
let realY = data.y;6
const realDepsX = [];7
const realDepsY = [];8
9
// track and trigger a property10
11
12
13
14
15
const triggerX = () => {16
realDepsX.forEach((dep) => dep());17
};18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
const triggerX = () => {
realDepsX.forEach((dep) => dep());
};
// data1
const data = { x: 3, y: 6 };2
3
// real data and deps behind4
let realX = data.x;5
let realY = data.y;6
const realDepsX = [];7
const realDepsY = [];8
9
// track and trigger a property10
const trackX = () => {11
if (isDryRun && currentDep) {12
realDepsX.push(currentDep);13
}14
};15
16
17
18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
// data1
const data = { x: 3, y: 6 };2
3
// real data and deps behind4
let realX = data.x;5
let realY = data.y;6
const realDepsX = [];7
const realDepsY = [];8
9
// track and trigger a property10
const trackX = () => {11
if (isDryRun && currentDep) {12
realDepsX.push(currentDep);13
}14
};15
const triggerX = () => {16
realDepsX.forEach((dep) => dep());17
};18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
// data1
const data = { x: 3, y: 6 };2
3
// real data and deps behind4
let realX = data.x;5
let realY = data.y;6
const realDepsX = [];7
const realDepsY = [];8
9
// track and trigger a property10
const trackX = () => {11
if (isDryRun && currentDep) {12
realDepsX.push(currentDep);13
}14
};15
const triggerX = () => {16
realDepsX.forEach((dep) => dep());17
};18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
// data1
const data = { x: 3, y: 6 };2
3
// real data and deps behind4
let realX = data.x;5
let realY = data.y;6
const realDepsX = [];7
const realDepsY = [];8
9
// track and trigger a property10
const trackX = () => {11
if (isDryRun && currentDep) {12
realDepsX.push(currentDep);13
}14
};15
const triggerX = () => {16
realDepsX.forEach((dep) => dep());17
};18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
watch(depA);
watch(depB);
watch(depC);
let currentDep = null;55
const watch = (fn) => {56
isDryRun = true;57
currentDep = fn;58
fn();59
currentDep = null;60
isDryRun = false;61
};62
63
// define 3 functions64
const depA = () => console.log(`x = ${data.x}`);65
const depB = () => console.log(`y = ${data.y}`);66
const depC = () => console.log(`x + y = ${data.x + data.y}`);67
68
// dry-run all dependents69
70
71
72
// output: x = 3, y = 6, x + y = 973
74
75
// mutate data76
data.x = 6;77
// output: x = 6, x + y = 1278
79
data.y = 9;80
9
20. // data
const data = { x: 3, y: 6 };
// real data and deps behind
let realX = data.x;
let realY = data.y;
const realDepsX = [];
const realDepsY = [];
// track and trigger a property
const trackX = () => {
if (isDryRun && currentDep) {
realDepsX.push(currentDep);
}
};
const triggerX = () => {
realDepsX.forEach((dep) => dep());
};
const trackY = () => {
if (isDryRun && currentDep) {
realDepsY.push(currentDep);
}
};
const triggerY = () => {
realDepsY.forEach((dep) => dep());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const data = { x: 3, y: 6 };
// data1
2
3
// real data and deps behind4
let realX = data.x;5
let realY = data.y;6
const realDepsX = [];7
const realDepsY = [];8
9
// track and trigger a property10
const trackX = () => {11
if (isDryRun && currentDep) {12
realDepsX.push(currentDep);13
}14
};15
const triggerX = () => {16
realDepsX.forEach((dep) => dep());17
};18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
let realX = data.x;
let realY = data.y;
// data1
const data = { x: 3, y: 6 };2
3
// real data and deps behind4
5
6
const realDepsX = [];7
const realDepsY = [];8
9
// track and trigger a property10
const trackX = () => {11
if (isDryRun && currentDep) {12
realDepsX.push(currentDep);13
}14
};15
const triggerX = () => {16
realDepsX.forEach((dep) => dep());17
};18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
const realDepsX = [];
const realDepsY = [];
// data1
const data = { x: 3, y: 6 };2
3
// real data and deps behind4
let realX = data.x;5
let realY = data.y;6
7
8
9
// track and trigger a property10
const trackX = () => {11
if (isDryRun && currentDep) {12
realDepsX.push(currentDep);13
}14
};15
const triggerX = () => {16
realDepsX.forEach((dep) => dep());17
};18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
const trackX = () => {
if (isDryRun && currentDep) {
realDepsX.push(currentDep);
}
};
// data1
const data = { x: 3, y: 6 };2
3
// real data and deps behind4
let realX = data.x;5
let realY = data.y;6
const realDepsX = [];7
const realDepsY = [];8
9
// track and trigger a property10
11
12
13
14
15
const triggerX = () => {16
realDepsX.forEach((dep) => dep());17
};18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
const triggerX = () => {
realDepsX.forEach((dep) => dep());
};
// data1
const data = { x: 3, y: 6 };2
3
// real data and deps behind4
let realX = data.x;5
let realY = data.y;6
const realDepsX = [];7
const realDepsY = [];8
9
// track and trigger a property10
const trackX = () => {11
if (isDryRun && currentDep) {12
realDepsX.push(currentDep);13
}14
};15
16
17
18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
// data1
const data = { x: 3, y: 6 };2
3
// real data and deps behind4
let realX = data.x;5
let realY = data.y;6
const realDepsX = [];7
const realDepsY = [];8
9
// track and trigger a property10
const trackX = () => {11
if (isDryRun && currentDep) {12
realDepsX.push(currentDep);13
}14
};15
const triggerX = () => {16
realDepsX.forEach((dep) => dep());17
};18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
// data1
const data = { x: 3, y: 6 };2
3
// real data and deps behind4
let realX = data.x;5
let realY = data.y;6
const realDepsX = [];7
const realDepsY = [];8
9
// track and trigger a property10
const trackX = () => {11
if (isDryRun && currentDep) {12
realDepsX.push(currentDep);13
}14
};15
const triggerX = () => {16
realDepsX.forEach((dep) => dep());17
};18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
// data1
const data = { x: 3, y: 6 };2
3
// real data and deps behind4
let realX = data.x;5
let realY = data.y;6
const realDepsX = [];7
const realDepsY = [];8
9
// track and trigger a property10
const trackX = () => {11
if (isDryRun && currentDep) {12
realDepsX.push(currentDep);13
}14
};15
const triggerX = () => {16
realDepsX.forEach((dep) => dep());17
};18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
// data1
const data = { x: 3, y: 6 };2
3
// real data and deps behind4
let realX = data.x;5
let realY = data.y;6
const realDepsX = [];7
const realDepsY = [];8
9
// track and trigger a property10
const trackX = () => {11
if (isDryRun && currentDep) {12
realDepsX.push(currentDep);13
}14
};15
const triggerX = () => {16
realDepsX.forEach((dep) => dep());17
};18
19
const trackY = () => {20
if (isDryRun && currentDep) {21
realDepsY.push(currentDep);22
}23
};24
const triggerY = () => {25
realDepsY.forEach((dep) => dep());26
}27
data.x = 6;
data.y = 9;
let currentDep = null;55
const watch = (fn) => {56
isDryRun = true;57
currentDep = fn;58
fn();59
currentDep = null;60
isDryRun = false;61
};62
63
// define 3 functions64
const depA = () => console.log(`x = ${data.x}`);65
const depB = () => console.log(`y = ${data.y}`);66
const depC = () => console.log(`x + y = ${data.x + data.y}`);67
68
// dry-run all dependents69
watch(depA);70
watch(depB);71
watch(depC);72
// output: x = 3, y = 6, x + y = 973
74
75
// mutate data76
77
// output: x = 6, x + y = 1278
79
80
9
21. Problems:
Setting array items by assigning value to a certain index. (e.g. arr[0] =
value)
Setting the length of an array. (e.g. arr.length = 0)
Adding a new property to an object. (e.g. obj.newKey = value) So it needs
some complementary APIs like Vue.$set(obj, newKey, value).
10
22. // data
const data = { x: 3, y: 6 };
// a Map to record dependets
const dependentMap = new Map()
// track and trigger a property
const track = (type, data, propName) => {
if (isDryRun && currentFn) {
/* checking */
if (!dependentMap.has(data)) {
dependentMap.set(data, new Map())
}
/* checking */
if (!dependentMap.get(data).has(propName)) {
dependentMap.get(data).set(propName, new Set())
}
dependentMap.get(data).get(propName).add(currentFn)
}
}
const trigger = (type, data, propName) => {
dependentMap.get(data).get(propName).forEach(fn => fn())
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
11
23. // data
const data = { x: 3, y: 6 };
// a Map to record dependets
const dependentMap = new Map()
// track and trigger a property
const track = (type, data, propName) => {
if (isDryRun && currentFn) {
/* checking */
if (!dependentMap.has(data)) {
dependentMap.set(data, new Map())
}
/* checking */
if (!dependentMap.get(data).has(propName)) {
dependentMap.get(data).set(propName, new Set())
}
dependentMap.get(data).get(propName).add(currentFn)
}
}
const trigger = (type, data, propName) => {
dependentMap.get(data).get(propName).forEach(fn => fn())
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const data = { x: 3, y: 6 };
const dependentMap = new Map()
// data1
2
3
// a Map to record dependets4
5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
11
24. // data
const data = { x: 3, y: 6 };
// a Map to record dependets
const dependentMap = new Map()
// track and trigger a property
const track = (type, data, propName) => {
if (isDryRun && currentFn) {
/* checking */
if (!dependentMap.has(data)) {
dependentMap.set(data, new Map())
}
/* checking */
if (!dependentMap.get(data).has(propName)) {
dependentMap.get(data).set(propName, new Set())
}
dependentMap.get(data).get(propName).add(currentFn)
}
}
const trigger = (type, data, propName) => {
dependentMap.get(data).get(propName).forEach(fn => fn())
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const data = { x: 3, y: 6 };
const dependentMap = new Map()
// data1
2
3
// a Map to record dependets4
5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
const track = (type, data, propName) => {
if (isDryRun && currentFn) {
/* checking */
if (!dependentMap.has(data)) {
dependentMap.set(data, new Map())
}
/* checking */
if (!dependentMap.get(data).has(propName)) {
dependentMap.get(data).set(propName, new Set())
}
dependentMap.get(data).get(propName).add(currentFn)
}
}
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
8
9
10
11
12
13
14
15
16
17
18
19
20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
const proxy = new Proxy(data, {25
get(...args) {26
track("get", ...args);27
11
25. // data
const data = { x: 3, y: 6 };
// a Map to record dependets
const dependentMap = new Map()
// track and trigger a property
const track = (type, data, propName) => {
if (isDryRun && currentFn) {
/* checking */
if (!dependentMap.has(data)) {
dependentMap.set(data, new Map())
}
/* checking */
if (!dependentMap.get(data).has(propName)) {
dependentMap.get(data).set(propName, new Set())
}
dependentMap.get(data).get(propName).add(currentFn)
}
}
const trigger = (type, data, propName) => {
dependentMap.get(data).get(propName).forEach(fn => fn())
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const data = { x: 3, y: 6 };
const dependentMap = new Map()
// data1
2
3
// a Map to record dependets4
5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
const track = (type, data, propName) => {
if (isDryRun && currentFn) {
/* checking */
if (!dependentMap.has(data)) {
dependentMap.set(data, new Map())
}
/* checking */
if (!dependentMap.get(data).has(propName)) {
dependentMap.get(data).set(propName, new Set())
}
dependentMap.get(data).get(propName).add(currentFn)
}
}
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
8
9
10
11
12
13
14
15
16
17
18
19
20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
const trigger = (type, data, propName) => {
dependentMap.get(data).get(propName).forEach(fn => fn())
}
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
21
22
23
24
const proxy = new Proxy(data, {25
get(...args) {26
track("get", ...args);27
return Reflect.get(...args);28
},29
set(...args) {30
Reflect.set(...args);31
trigger("set", ...args);32
},33
});34
35
11
26. // data
const data = { x: 3, y: 6 };
// a Map to record dependets
const dependentMap = new Map()
// track and trigger a property
const track = (type, data, propName) => {
if (isDryRun && currentFn) {
/* checking */
if (!dependentMap.has(data)) {
dependentMap.set(data, new Map())
}
/* checking */
if (!dependentMap.get(data).has(propName)) {
dependentMap.get(data).set(propName, new Set())
}
dependentMap.get(data).get(propName).add(currentFn)
}
}
const trigger = (type, data, propName) => {
dependentMap.get(data).get(propName).forEach(fn => fn())
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const data = { x: 3, y: 6 };
const dependentMap = new Map()
// data1
2
3
// a Map to record dependets4
5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
const track = (type, data, propName) => {
if (isDryRun && currentFn) {
/* checking */
if (!dependentMap.has(data)) {
dependentMap.set(data, new Map())
}
/* checking */
if (!dependentMap.get(data).has(propName)) {
dependentMap.get(data).set(propName, new Set())
}
dependentMap.get(data).get(propName).add(currentFn)
}
}
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
8
9
10
11
12
13
14
15
16
17
18
19
20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
const trigger = (type, data, propName) => {
dependentMap.get(data).get(propName).forEach(fn => fn())
}
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
21
22
23
24
const proxy = new Proxy(data, {
get(...args) {
track("get", ...args);
return Reflect.get(...args);
},
set(...args) {
Reflect.set(...args);
trigger("set", ...args);
},
});
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
25
26
27
28
29
30
31
32
33
34
35
// watch functions36
const depA = () => console.log(`x = ${proxy.x}`)37
const depB = () => console.log(`y = ${proxy.y}`)38
const depC = () => console.log(`x + y = ${proxy.x + proxy.y}`)39
40
// watch41
let isDryRun = false42
11
27. // data
const data = { x: 3, y: 6 };
// a Map to record dependets
const dependentMap = new Map()
// track and trigger a property
const track = (type, data, propName) => {
if (isDryRun && currentFn) {
/* checking */
if (!dependentMap.has(data)) {
dependentMap.set(data, new Map())
}
/* checking */
if (!dependentMap.get(data).has(propName)) {
dependentMap.get(data).set(propName, new Set())
}
dependentMap.get(data).get(propName).add(currentFn)
}
}
const trigger = (type, data, propName) => {
dependentMap.get(data).get(propName).forEach(fn => fn())
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const data = { x: 3, y: 6 };
const dependentMap = new Map()
// data1
2
3
// a Map to record dependets4
5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
const track = (type, data, propName) => {
if (isDryRun && currentFn) {
/* checking */
if (!dependentMap.has(data)) {
dependentMap.set(data, new Map())
}
/* checking */
if (!dependentMap.get(data).has(propName)) {
dependentMap.get(data).set(propName, new Set())
}
dependentMap.get(data).get(propName).add(currentFn)
}
}
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
8
9
10
11
12
13
14
15
16
17
18
19
20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
const trigger = (type, data, propName) => {
dependentMap.get(data).get(propName).forEach(fn => fn())
}
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
21
22
23
24
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
get(...args) {
track("get", ...args);
return Reflect.get(...args);
},
/ checking /14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
const proxy = new Proxy(data, {25
26
27
28
29
set(...args) {30
Reflect.set(...args);31
trigger("set", ...args);32
},33
});34
35
// watch functions36
const depA = () => console.log(`x = ${proxy.x}`)37
const depB = () => console.log(`y = ${proxy.y}`)38
const depC = () => console.log(`x + y = ${proxy.x + proxy.y}`)39
40
11
28. // data
const data = { x: 3, y: 6 };
// a Map to record dependets
const dependentMap = new Map()
// track and trigger a property
const track = (type, data, propName) => {
if (isDryRun && currentFn) {
/* checking */
if (!dependentMap.has(data)) {
dependentMap.set(data, new Map())
}
/* checking */
if (!dependentMap.get(data).has(propName)) {
dependentMap.get(data).set(propName, new Set())
}
dependentMap.get(data).get(propName).add(currentFn)
}
}
const trigger = (type, data, propName) => {
dependentMap.get(data).get(propName).forEach(fn => fn())
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const data = { x: 3, y: 6 };
const dependentMap = new Map()
// data1
2
3
// a Map to record dependets4
5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
const track = (type, data, propName) => {
if (isDryRun && currentFn) {
/* checking */
if (!dependentMap.has(data)) {
dependentMap.set(data, new Map())
}
/* checking */
if (!dependentMap.get(data).has(propName)) {
dependentMap.get(data).set(propName, new Set())
}
dependentMap.get(data).get(propName).add(currentFn)
}
}
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
8
9
10
11
12
13
14
15
16
17
18
19
20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
const trigger = (type, data, propName) => {
dependentMap.get(data).get(propName).forEach(fn => fn())
}
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
21
22
23
24
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
set(...args) {
Reflect.set(...args);
trigger("set", ...args);
},
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
const proxy = new Proxy(data, {25
get(...args) {26
track("get", ...args);27
return Reflect.get(...args);28
},29
30
31
32
33
});34
35
// watch functions36
const depA = () => console.log(`x = ${proxy.x}`)37
const depB = () => console.log(`y = ${proxy.y}`)38
const depC = () => console.log(`x + y = ${proxy.x + proxy.y}`)39
40
// watch41
let isDryRun = false42
let currentFn = null43
const watch = fn => {44
11
29. // data
const data = { x: 3, y: 6 };
// a Map to record dependets
const dependentMap = new Map()
// track and trigger a property
const track = (type, data, propName) => {
if (isDryRun && currentFn) {
/* checking */
if (!dependentMap.has(data)) {
dependentMap.set(data, new Map())
}
/* checking */
if (!dependentMap.get(data).has(propName)) {
dependentMap.get(data).set(propName, new Set())
}
dependentMap.get(data).get(propName).add(currentFn)
}
}
const trigger = (type, data, propName) => {
dependentMap.get(data).get(propName).forEach(fn => fn())
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const data = { x: 3, y: 6 };
const dependentMap = new Map()
// data1
2
3
// a Map to record dependets4
5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
const track = (type, data, propName) => {
if (isDryRun && currentFn) {
/* checking */
if (!dependentMap.has(data)) {
dependentMap.set(data, new Map())
}
/* checking */
if (!dependentMap.get(data).has(propName)) {
dependentMap.get(data).set(propName, new Set())
}
dependentMap.get(data).get(propName).add(currentFn)
}
}
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
8
9
10
11
12
13
14
15
16
17
18
19
20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
const trigger = (type, data, propName) => {
dependentMap.get(data).get(propName).forEach(fn => fn())
}
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
21
22
23
24
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
const depA = () => console.log(`x = ${proxy.x}`)
const depB = () => console.log(`y = ${proxy.y}`)
const depC = () => console.log(`x + y = ${proxy.x + proxy.y}`)
const proxy = new Proxy(data, {25
get(...args) {26
track("get", ...args);27
return Reflect.get(...args);28
},29
set(...args) {30
Reflect.set(...args);31
trigger("set", ...args);32
},33
});34
35
// watch functions36
37
38
39
40
// watch41
let isDryRun = false42
let currentFn = null43
const watch = fn => {44
isDryRun = true45
currentFn = fn46
fn()47
currentFn = null48
isDryRun = false49
}50
51
11
30. // data
const data = { x: 3, y: 6 };
// a Map to record dependets
const dependentMap = new Map()
// track and trigger a property
const track = (type, data, propName) => {
if (isDryRun && currentFn) {
/* checking */
if (!dependentMap.has(data)) {
dependentMap.set(data, new Map())
}
/* checking */
if (!dependentMap.get(data).has(propName)) {
dependentMap.get(data).set(propName, new Set())
}
dependentMap.get(data).get(propName).add(currentFn)
}
}
const trigger = (type, data, propName) => {
dependentMap.get(data).get(propName).forEach(fn => fn())
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const data = { x: 3, y: 6 };
const dependentMap = new Map()
// data1
2
3
// a Map to record dependets4
5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
const track = (type, data, propName) => {
if (isDryRun && currentFn) {
/* checking */
if (!dependentMap.has(data)) {
dependentMap.set(data, new Map())
}
/* checking */
if (!dependentMap.get(data).has(propName)) {
dependentMap.get(data).set(propName, new Set())
}
dependentMap.get(data).get(propName).add(currentFn)
}
}
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
8
9
10
11
12
13
14
15
16
17
18
19
20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
const trigger = (type, data, propName) => {
dependentMap.get(data).get(propName).forEach(fn => fn())
}
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
21
22
23
24
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
const watch = fn => {
isDryRun = true
currentFn = fn
fn()
currentFn = null
isDryRun = false
}
});34
35
// watch functions36
const depA = () => console.log(`x = ${proxy.x}`)37
const depB = () => console.log(`y = ${proxy.y}`)38
const depC = () => console.log(`x + y = ${proxy.x + proxy.y}`)39
40
// watch41
let isDryRun = false42
let currentFn = null43
44
45
46
47
48
49
50
51
watch(depA);52
watch(depB);53
watch(depC);54
// output: x = 3, y = 6, x + y = 955
56
// mutate data57
proxy.x = 6;58
// output: x = 6, x + y = 1259
60
11
31. // data
const data = { x: 3, y: 6 };
// a Map to record dependets
const dependentMap = new Map()
// track and trigger a property
const track = (type, data, propName) => {
if (isDryRun && currentFn) {
/* checking */
if (!dependentMap.has(data)) {
dependentMap.set(data, new Map())
}
/* checking */
if (!dependentMap.get(data).has(propName)) {
dependentMap.get(data).set(propName, new Set())
}
dependentMap.get(data).get(propName).add(currentFn)
}
}
const trigger = (type, data, propName) => {
dependentMap.get(data).get(propName).forEach(fn => fn())
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const data = { x: 3, y: 6 };
const dependentMap = new Map()
// data1
2
3
// a Map to record dependets4
5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
const track = (type, data, propName) => {
if (isDryRun && currentFn) {
/* checking */
if (!dependentMap.has(data)) {
dependentMap.set(data, new Map())
}
/* checking */
if (!dependentMap.get(data).has(propName)) {
dependentMap.get(data).set(propName, new Set())
}
dependentMap.get(data).get(propName).add(currentFn)
}
}
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
8
9
10
11
12
13
14
15
16
17
18
19
20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
const trigger = (type, data, propName) => {
dependentMap.get(data).get(propName).forEach(fn => fn())
}
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
21
22
23
24
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
watch(depA);
watch(depB);
watch(depC);
// output: x = 3, y = 6, x + y = 9
const depA = () => console.log(`x = ${proxy.x}`)37
const depB = () => console.log(`y = ${proxy.y}`)38
const depC = () => console.log(`x + y = ${proxy.x + proxy.y}`)39
40
// watch41
let isDryRun = false42
let currentFn = null43
const watch = fn => {44
isDryRun = true45
currentFn = fn46
fn()47
currentFn = null48
isDryRun = false49
}50
51
52
53
54
55
56
// mutate data57
proxy.x = 6;58
// output: x = 6, x + y = 1259
60
proxy.y = 9;61
// output: y = 9, x + y = 1562
11
32. // data
const data = { x: 3, y: 6 };
// a Map to record dependets
const dependentMap = new Map()
// track and trigger a property
const track = (type, data, propName) => {
if (isDryRun && currentFn) {
/* checking */
if (!dependentMap.has(data)) {
dependentMap.set(data, new Map())
}
/* checking */
if (!dependentMap.get(data).has(propName)) {
dependentMap.get(data).set(propName, new Set())
}
dependentMap.get(data).get(propName).add(currentFn)
}
}
const trigger = (type, data, propName) => {
dependentMap.get(data).get(propName).forEach(fn => fn())
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const data = { x: 3, y: 6 };
const dependentMap = new Map()
// data1
2
3
// a Map to record dependets4
5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
const track = (type, data, propName) => {
if (isDryRun && currentFn) {
/* checking */
if (!dependentMap.has(data)) {
dependentMap.set(data, new Map())
}
/* checking */
if (!dependentMap.get(data).has(propName)) {
dependentMap.get(data).set(propName, new Set())
}
dependentMap.get(data).get(propName).add(currentFn)
}
}
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
8
9
10
11
12
13
14
15
16
17
18
19
20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
const trigger = (type, data, propName) => {
dependentMap.get(data).get(propName).forEach(fn => fn())
}
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
21
22
23
24
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
// data1
const data = { x: 3, y: 6 };2
3
// a Map to record dependets4
const dependentMap = new Map()5
6
// track and trigger a property7
const track = (type, data, propName) => {8
if (isDryRun && currentFn) {9
/* checking */10
if (!dependentMap.has(data)) {11
dependentMap.set(data, new Map())12
}13
/* checking */14
if (!dependentMap.get(data).has(propName)) {15
dependentMap.get(data).set(propName, new Set())16
}17
dependentMap.get(data).get(propName).add(currentFn)18
}19
}20
const trigger = (type, data, propName) => {21
dependentMap.get(data).get(propName).forEach(fn => fn())22
}23
24
proxy.x = 6;
proxy.y = 9;
const depA = () => console.log(`x = ${proxy.x}`)37
const depB = () => console.log(`y = ${proxy.y}`)38
const depC = () => console.log(`x + y = ${proxy.x + proxy.y}`)39
40
// watch41
let isDryRun = false42
let currentFn = null43
const watch = fn => {44
isDryRun = true45
currentFn = fn46
fn()47
currentFn = null48
isDryRun = false49
}50
51
watch(depA);52
watch(depB);53
watch(depC);54
// output: x = 3, y = 6, x + y = 955
56
// mutate data57
58
// output: x = 6, x + y = 1259
60
61
// output: y = 9, x + y = 1562
11
33. Conclusion
- ES6 Proxy solution reactivity
- Reflect helps with better binding to `this`
- No more relying on `Object.defineProperty`
- Reactivity is abstracted from the component instance
12
34. Links
Vue reactivity in Depth
https://vuejs.org/v2/guide/reactivity.html
Understand Vue Reactivity Implementation Step by Step
https://medium.com/js-dojo/understand-vue-reactivity-implementation-step-by-step-
599c3d51cd6c
Vue 3
https://github.com/vuejs/vue-next
13