Skip to content

Commit 775f9b5

Browse files
authored
fix: Avoid recursion by using markHybridObject with rolling counter (#57)
1 parent 71dd0c4 commit 775f9b5

3 files changed

Lines changed: 32 additions & 10 deletions

File tree

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { type AsyncImageSource, isHybridObject } from "./AsyncImageSource";
2+
import type { Image } from "./specs/Image.nitro";
3+
import type { ImageLoader } from "./specs/ImageLoader.nitro";
4+
5+
let counter = 0;
6+
export function markHybridObject(
7+
object: Image | ImageLoader,
8+
source: AsyncImageSource,
9+
): typeof object {
10+
if (isHybridObject(source)) {
11+
// `source` is a HybridObject - to avoid recursion, we just set it to an incrementing counter.
12+
Object.defineProperty(object, "__source", {
13+
enumerable: true,
14+
configurable: true,
15+
value: counter,
16+
});
17+
counter++;
18+
} else {
19+
// `source` is just an input object, we can use it to tag the Image properly
20+
Object.defineProperty(object, "__source", {
21+
enumerable: true,
22+
configurable: true,
23+
value: source,
24+
});
25+
}
26+
return object;
27+
}

packages/react-native-nitro-image/src/useImage.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useEffect, useState } from "react";
22
import { type AsyncImageSource, isHybridObject } from "./AsyncImageSource";
33
import { loadImage } from "./loadImage";
4+
import { markHybridObject } from "./markHybridObject";
45
import type { Image } from "./specs/Image.nitro";
56

67
type Result =
@@ -41,11 +42,8 @@ export function useImage(source: AsyncImageSource): Result {
4142
// 1. Create the Image/ImageLoader instance
4243
const result = await loadImage(source);
4344
// 2. Add `__source` as a property on the JS side so React diffs properly
44-
Object.defineProperty(result, "__source", {
45-
enumerable: true,
46-
configurable: true,
47-
value: source,
48-
});
45+
markHybridObject(result, source);
46+
// 3. Update the state
4947
setImage({ image: result, error: undefined });
5048
} catch (e) {
5149
const error = e instanceof Error ? e : new Error(`${e}`);

packages/react-native-nitro-image/src/useImageLoader.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useMemo } from "react";
22
import { type AsyncImageSource, isHybridObject } from "./AsyncImageSource";
33
import { createImageLoader } from "./createImageLoader";
4+
import { markHybridObject } from "./markHybridObject";
45
import type { Image } from "./specs/Image.nitro";
56
import type { ImageLoader } from "./specs/ImageLoader.nitro";
67

@@ -12,11 +13,7 @@ export function useImageLoader(
1213
// 1. Create the Image/ImageLoader instance
1314
const loader = createImageLoader(source);
1415
// 2. Add `__source` as a property on the JS side so React diffs properly
15-
Object.defineProperty(loader, "__source", {
16-
enumerable: true,
17-
configurable: true,
18-
value: source,
19-
});
16+
markHybridObject(loader, source);
2017
// 3. Return it
2118
return loader;
2219
}, [isHybridObject(source) ? source : JSON.stringify(source)]);

0 commit comments

Comments
 (0)