forked from mobxjs/mobx
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdynamicobject.ts
More file actions
74 lines (71 loc) · 2.77 KB
/
Copy pathdynamicobject.ts
File metadata and controls
74 lines (71 loc) · 2.77 KB
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import {
$mobx,
Atom,
IIsObservableObject,
ObservableObjectAdministration,
fail,
mobxDidRunLazyInitializersSymbol,
set
} from "../internal"
function getAdm(target): ObservableObjectAdministration {
return target[$mobx]
}
// Optimization: we don't need the intermediate objects and could have a completely custom administration for DynamicObjects,
// and skip either the internal values map, or the base object with its property descriptors!
const objectProxyTraps: ProxyHandler<any> = {
has(target: IIsObservableObject, name: PropertyKey) {
if (name === $mobx || name === "constructor" || name === mobxDidRunLazyInitializersSymbol)
return true
const adm = getAdm(target)
// MWE: should `in` operator be reactive? If not, below code path will be faster / more memory efficient
// TODO: check performance stats!
// if (adm.values.get(name as string)) return true
if (typeof name === "string") return adm.has(name)
return (name as any) in target
},
get(target: IIsObservableObject, name: PropertyKey) {
if (name === $mobx || name === "constructor" || name === mobxDidRunLazyInitializersSymbol)
return target[name]
const adm = getAdm(target)
const observable = adm.values.get(name as string)
if (observable instanceof Atom) {
const result = (observable as any).get()
if (result === undefined) {
// This fixes #1796, because deleting a prop that has an
// undefined value won't retrigger a observer (no visible effect),
// the autorun wouldn't subscribe to future key changes (see also next comment)
adm.has(name as any)
}
return result
}
// make sure we start listening to future keys
// note that we only do this here for optimization
if (typeof name === "string") adm.has(name)
return target[name]
},
set(target: IIsObservableObject, name: PropertyKey, value: any) {
if (typeof name !== "string") return false
set(target, name, value)
return true
},
deleteProperty(target: IIsObservableObject, name: PropertyKey) {
if (typeof name !== "string") return false
const adm = getAdm(target)
adm.remove(name)
return true
},
ownKeys(target: IIsObservableObject) {
const adm = getAdm(target)
adm.keysAtom.reportObserved()
return Reflect.ownKeys(target)
},
preventExtensions(target) {
fail(`Dynamic observable objects cannot be frozen`)
return false
}
}
export function createDynamicObservableObject(base) {
const proxy = new Proxy(base, objectProxyTraps)
base[$mobx].proxy = proxy
return proxy
}