From e1f06c61101f3dc51b5fc9f700030ba18fbaf3a5 Mon Sep 17 00:00:00 2001 From: Peter Marshall Date: Mon, 19 Aug 2024 11:38:41 +1000 Subject: [PATCH] Use a Map for createTransformer memoization --- src/create-transformer.ts | 42 +++++++++++++++++++------------------- test/create-transformer.ts | 4 ++-- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/create-transformer.ts b/src/create-transformer.ts index 2ace372..5d045c4 100644 --- a/src/create-transformer.ts +++ b/src/create-transformer.ts @@ -5,7 +5,7 @@ import { _isComputingDerivation, IComputedValueOptions, } from "mobx" -import { invariant, addHiddenProp } from "./utils" +import { invariant } from "./utils" export type ITransformer = (object: A) => B @@ -15,8 +15,6 @@ export type ITransformerParams = { keepAlive?: boolean } & Omit, "name"> -let memoizationId = 0 - export function createTransformer( transformer: ITransformer, onCleanup?: (resultObject: B | undefined, sourceObject?: A) => void @@ -43,8 +41,8 @@ export function createTransformer( "createTransformer expects a function that accepts one argument" ) - // Memoizes: object id -> reactive view that applies transformer to the object - let views: { [id: number]: IComputedValue } = {} + // Memoizes: object -> reactive view that applies transformer to the object + const views = new Map>() let onCleanup: Function | undefined = undefined let keepAlive: boolean = false let debugNameGenerator: Function | undefined = undefined @@ -56,7 +54,7 @@ export function createTransformer( onCleanup = arg2 } - function createView(sourceIdentifier: number, sourceObject: A) { + function createView(sourceObject: A) { let latestValue: B let computedValueOptions = {} if (typeof arg2 === "object") { @@ -69,9 +67,12 @@ export function createTransformer( onCleanup = undefined debugNameGenerator = undefined } + const sourceType = typeof sourceObject const prettifiedName = debugNameGenerator ? debugNameGenerator(sourceObject) - : `Transformer-${(transformer).name}-${sourceIdentifier}` + : `Transformer-${(transformer).name}-${ + sourceType === "string" || sourceType === "number" ? sourceObject : "object" + }` const expr = computed( () => { return (latestValue = transformer(sourceObject)) @@ -83,7 +84,7 @@ export function createTransformer( ) if (!keepAlive) { const disposer = onBecomeUnobserved(expr, () => { - delete views[sourceIdentifier] + views.delete(sourceObject) disposer() if (onCleanup) onCleanup(latestValue, sourceObject) }) @@ -93,8 +94,8 @@ export function createTransformer( let memoWarned = false return (object: A) => { - const identifier = getMemoizationId(object) - let reactiveView = views[identifier] + checkTransformableObject(object) + let reactiveView = views.get(object) if (reactiveView) return reactiveView.get() if (!keepAlive && !_isComputingDerivation()) { if (!memoWarned) { @@ -109,25 +110,24 @@ export function createTransformer( return value } // Not in cache; create a reactive view - reactiveView = views[identifier] = createView(identifier, object) + reactiveView = createView(object) + views.set(object, reactiveView) return reactiveView.get() } } -function getMemoizationId(object: any) { +function checkTransformableObject(object: any) { const objectType = typeof object - if (objectType === "string") return `string:${object}` - if (objectType === "number") return `number:${object}` - if (object === null || (objectType !== "object" && objectType !== "function")) + if ( + object === null || + (objectType !== "object" && + objectType !== "function" && + objectType !== "string" && + objectType !== "number") + ) throw new Error( `[mobx-utils] transform expected an object, function, string or number, got: ${String( object )}` ) - let tid = object.$transformId - if (tid === undefined) { - tid = `memoizationId:${++memoizationId}` - addHiddenProp(object, "$transformId", tid) - } - return tid } diff --git a/test/create-transformer.ts b/test/create-transformer.ts index 8ae9717..3d804e4 100644 --- a/test/create-transformer.ts +++ b/test/create-transformer.ts @@ -72,10 +72,10 @@ test("transform1", () => { "name": "ObservableObject@1.todos[..].title", "observers": Array [ Object { - "name": "Transformer--memoizationId:3", + "name": "Transformer--object", "observers": Array [ Object { - "name": "Transformer--memoizationId:1", + "name": "Transformer--object", "observers": Array [ Object { "name": "Autorun@2",