@@ -5,21 +5,21 @@ import {
5
5
_isComputingDerivation ,
6
6
IComputedValueOptions ,
7
7
} from "mobx"
8
- import { invariant , addHiddenProp } from "./utils"
8
+ import { invariant } from "./utils"
9
9
10
10
export type ITransformer < A , B > = ( object : A ) => B
11
11
12
+ export type ITransformerCleanup < A , B > = ( resultObject : B | undefined , sourceObject ?: A ) => void
13
+
12
14
export type ITransformerParams < A , B > = {
13
- onCleanup ?: ( resultObject : B | undefined , sourceObject ?: A ) => void
15
+ onCleanup ?: ITransformerCleanup < A , B >
14
16
debugNameGenerator ?: ( sourceObject ?: A ) => string
15
17
keepAlive ?: boolean
16
18
} & Omit < IComputedValueOptions < B > , "name" >
17
19
18
- let memoizationId = 0
19
-
20
20
export function createTransformer < A , B > (
21
21
transformer : ITransformer < A , B > ,
22
- onCleanup ?: ( resultObject : B | undefined , sourceObject ?: A ) => void
22
+ onCleanup ?: ITransformerCleanup < A , B >
23
23
) : ITransformer < A , B >
24
24
export function createTransformer < A , B > (
25
25
transformer : ITransformer < A , B > ,
@@ -31,20 +31,22 @@ export function createTransformer<A, B>(
31
31
*
32
32
* See the [transformer](#createtransformer-in-detail) section for more details.
33
33
*
34
- * @param transformer
35
- * @param onCleanup
34
+ * @param transformer A function which transforms instances of A into instances of B
35
+ * @param arg2 An optional cleanup function which is called when the transformation is no longer
36
+ * observed from a reactive context, or config options
37
+ * @returns The memoized transformer function
36
38
*/
37
39
export function createTransformer < A , B > (
38
40
transformer : ITransformer < A , B > ,
39
- arg2 ?: any
41
+ arg2 ?: ITransformerParams < A , B > | ITransformerCleanup < A , B >
40
42
) : ITransformer < A , B > {
41
43
invariant (
42
44
typeof transformer === "function" && transformer . length < 2 ,
43
45
"createTransformer expects a function that accepts one argument"
44
46
)
45
47
46
- // Memoizes: object id -> reactive view that applies transformer to the object
47
- let views : { [ id : number ] : IComputedValue < B > } = { }
48
+ // Memoizes: object -> reactive view that applies transformer to the object
49
+ const views = new Map < A , IComputedValue < B > > ( )
48
50
let onCleanup : Function | undefined = undefined
49
51
let keepAlive : boolean = false
50
52
let debugNameGenerator : Function | undefined = undefined
@@ -56,7 +58,7 @@ export function createTransformer<A, B>(
56
58
onCleanup = arg2
57
59
}
58
60
59
- function createView ( sourceIdentifier : number , sourceObject : A ) {
61
+ function createView ( sourceObject : A ) {
60
62
let latestValue : B
61
63
let computedValueOptions = { }
62
64
if ( typeof arg2 === "object" ) {
@@ -69,9 +71,12 @@ export function createTransformer<A, B>(
69
71
onCleanup = undefined
70
72
debugNameGenerator = undefined
71
73
}
74
+ const sourceType = typeof sourceObject
72
75
const prettifiedName = debugNameGenerator
73
76
? debugNameGenerator ( sourceObject )
74
- : `Transformer-${ ( < any > transformer ) . name } -${ sourceIdentifier } `
77
+ : `Transformer-${ ( < any > transformer ) . name } -${
78
+ sourceType === "string" || sourceType === "number" ? sourceObject : "object"
79
+ } `
75
80
const expr = computed (
76
81
( ) => {
77
82
return ( latestValue = transformer ( sourceObject ) )
@@ -83,7 +88,7 @@ export function createTransformer<A, B>(
83
88
)
84
89
if ( ! keepAlive ) {
85
90
const disposer = onBecomeUnobserved ( expr , ( ) => {
86
- delete views [ sourceIdentifier ]
91
+ views . delete ( sourceObject )
87
92
disposer ( )
88
93
if ( onCleanup ) onCleanup ( latestValue , sourceObject )
89
94
} )
@@ -93,8 +98,8 @@ export function createTransformer<A, B>(
93
98
94
99
let memoWarned = false
95
100
return ( object : A ) => {
96
- const identifier = getMemoizationId ( object )
97
- let reactiveView = views [ identifier ]
101
+ checkTransformableObject ( object )
102
+ let reactiveView = views . get ( object )
98
103
if ( reactiveView ) return reactiveView . get ( )
99
104
if ( ! keepAlive && ! _isComputingDerivation ( ) ) {
100
105
if ( ! memoWarned ) {
@@ -109,25 +114,24 @@ export function createTransformer<A, B>(
109
114
return value
110
115
}
111
116
// Not in cache; create a reactive view
112
- reactiveView = views [ identifier ] = createView ( identifier , object )
117
+ reactiveView = createView ( object )
118
+ views . set ( object , reactiveView )
113
119
return reactiveView . get ( )
114
120
}
115
121
}
116
122
117
- function getMemoizationId ( object : any ) {
123
+ function checkTransformableObject ( object : any ) {
118
124
const objectType = typeof object
119
- if ( objectType === "string" ) return `string:${ object } `
120
- if ( objectType === "number" ) return `number:${ object } `
121
- if ( object === null || ( objectType !== "object" && objectType !== "function" ) )
125
+ if (
126
+ object === null ||
127
+ ( objectType !== "object" &&
128
+ objectType !== "function" &&
129
+ objectType !== "string" &&
130
+ objectType !== "number" )
131
+ )
122
132
throw new Error (
123
133
`[mobx-utils] transform expected an object, function, string or number, got: ${ String (
124
134
object
125
135
) } `
126
136
)
127
- let tid = object . $transformId
128
- if ( tid === undefined ) {
129
- tid = `memoizationId:${ ++ memoizationId } `
130
- addHiddenProp ( object , "$transformId" , tid )
131
- }
132
- return tid
133
137
}
0 commit comments