@reearth/core 0.0.7-alpha.66 → 0.0.7-alpha.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core.js +556 -554
- package/dist/core.umd.cjs +41 -41
- package/package.json +1 -1
- package/src/engines/Cesium/core/Imagery.test.ts +91 -2
- package/src/engines/Cesium/core/Imagery.tsx +26 -5
package/package.json
CHANGED
|
@@ -1,10 +1,44 @@
|
|
|
1
1
|
import { renderHook } from "@testing-library/react";
|
|
2
2
|
import { UrlTemplateImageryProvider } from "cesium";
|
|
3
|
-
import { expect, test, vi } from "vitest";
|
|
3
|
+
import { expect, test, vi, beforeEach } from "vitest";
|
|
4
4
|
|
|
5
5
|
import type { CustomProviderConfig } from "../../../Map/types/customProvider";
|
|
6
6
|
|
|
7
|
-
import { type Tile, useImageryProviders } from "./Imagery";
|
|
7
|
+
import ImageryLayers, { type Tile, useImageryProviders } from "./Imagery";
|
|
8
|
+
|
|
9
|
+
// Mock Cesium scene and imageryLayerCollection for ImageryLayers component tests
|
|
10
|
+
const mockAdd = vi.fn();
|
|
11
|
+
const mockRemove = vi.fn();
|
|
12
|
+
const mockContains = vi.fn(() => true);
|
|
13
|
+
const mockIndexOf = vi.fn(() => 0);
|
|
14
|
+
const mockRequestRender = vi.fn();
|
|
15
|
+
|
|
16
|
+
const mockImageryLayerCollection = {
|
|
17
|
+
add: mockAdd,
|
|
18
|
+
remove: mockRemove,
|
|
19
|
+
contains: mockContains,
|
|
20
|
+
indexOf: mockIndexOf,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const mockScene = {
|
|
24
|
+
requestRender: mockRequestRender,
|
|
25
|
+
isDestroyed: () => false,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
vi.mock("resium", () => ({
|
|
29
|
+
useCesium: () => ({
|
|
30
|
+
imageryLayerCollection: mockImageryLayerCollection,
|
|
31
|
+
scene: mockScene,
|
|
32
|
+
}),
|
|
33
|
+
}));
|
|
34
|
+
|
|
35
|
+
beforeEach(() => {
|
|
36
|
+
mockAdd.mockClear();
|
|
37
|
+
mockRemove.mockClear();
|
|
38
|
+
mockContains.mockClear();
|
|
39
|
+
mockIndexOf.mockClear();
|
|
40
|
+
mockRequestRender.mockClear();
|
|
41
|
+
});
|
|
8
42
|
|
|
9
43
|
test("useImageryProviders", () => {
|
|
10
44
|
const provider = vi.fn(({ url }: { url?: string } = {}): any => ({ hoge: url }));
|
|
@@ -153,3 +187,58 @@ test("useImageryProviders", () => {
|
|
|
153
187
|
typedRerender({ tiles: [] });
|
|
154
188
|
expect(result.current.providers).toEqual({});
|
|
155
189
|
});
|
|
190
|
+
|
|
191
|
+
test("ImageryLayers should not re-render when tiles array reference changes but content is the same", async () => {
|
|
192
|
+
const tiles: Tile[] = [{ id: "1", type: "open_street_map", opacity: 0.8 }];
|
|
193
|
+
|
|
194
|
+
const { rerender } = renderHook(
|
|
195
|
+
({ tiles }: { tiles: Tile[] }) => {
|
|
196
|
+
return ImageryLayers({
|
|
197
|
+
tiles,
|
|
198
|
+
cesiumIonAccessToken: undefined,
|
|
199
|
+
customProvider: undefined,
|
|
200
|
+
onTilesChange: undefined,
|
|
201
|
+
});
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
initialProps: { tiles },
|
|
205
|
+
},
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
// Wait for initial render to complete
|
|
209
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
210
|
+
|
|
211
|
+
// Clear mock calls from initial render
|
|
212
|
+
mockAdd.mockClear();
|
|
213
|
+
mockRemove.mockClear();
|
|
214
|
+
|
|
215
|
+
// Re-render with a NEW tiles array reference but SAME content
|
|
216
|
+
const newTilesArraySameContent: Tile[] = [{ id: "1", type: "open_street_map", opacity: 0.8 }];
|
|
217
|
+
|
|
218
|
+
rerender({ tiles: newTilesArraySameContent });
|
|
219
|
+
|
|
220
|
+
// Wait for any effects to run
|
|
221
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
222
|
+
|
|
223
|
+
// Effect should NOT have run again - no layers should be removed or added
|
|
224
|
+
expect(mockRemove).not.toHaveBeenCalled();
|
|
225
|
+
expect(mockAdd).not.toHaveBeenCalled();
|
|
226
|
+
|
|
227
|
+
// Clear mocks
|
|
228
|
+
mockAdd.mockClear();
|
|
229
|
+
mockRemove.mockClear();
|
|
230
|
+
|
|
231
|
+
// Re-render with DIFFERENT content (changed opacity)
|
|
232
|
+
const differentTiles: Tile[] = [
|
|
233
|
+
{ id: "1", type: "open_street_map", opacity: 0.5 }, // opacity changed
|
|
234
|
+
];
|
|
235
|
+
|
|
236
|
+
rerender({ tiles: differentTiles });
|
|
237
|
+
|
|
238
|
+
// Wait for effects to run
|
|
239
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
240
|
+
|
|
241
|
+
// Effect SHOULD run - old layers removed and new ones added
|
|
242
|
+
expect(mockRemove).toHaveBeenCalled();
|
|
243
|
+
expect(mockAdd).toHaveBeenCalled();
|
|
244
|
+
});
|
|
@@ -53,8 +53,23 @@ export default function ImageryLayers({
|
|
|
53
53
|
}: Props) {
|
|
54
54
|
const { imageryLayerCollection, scene } = useCesium();
|
|
55
55
|
|
|
56
|
+
// Create a stable tiles reference that only changes when the content actually changes
|
|
57
|
+
// Normalize `undefined` to a stable empty array so `useImageryProviders` doesn't allocate a new default `[]` each render.
|
|
58
|
+
const emptyTiles = useMemo<Tile[]>(() => [], []);
|
|
59
|
+
const tilesValue = tiles ?? emptyTiles;
|
|
60
|
+
|
|
61
|
+
const prevTilesRef = useRef<Tile[]>(tilesValue);
|
|
62
|
+
const stableTiles = useMemo(() => {
|
|
63
|
+
if (!isEqual(prevTilesRef.current, tilesValue)) {
|
|
64
|
+
prevTilesRef.current = tilesValue;
|
|
65
|
+
}
|
|
66
|
+
return prevTilesRef.current;
|
|
67
|
+
}, [tilesValue]);
|
|
68
|
+
|
|
69
|
+
// Pass stableTiles to useImageryProviders to prevent providers from being recreated
|
|
70
|
+
// when tiles reference changes but content is the same
|
|
56
71
|
const { providers } = useImageryProviders({
|
|
57
|
-
tiles,
|
|
72
|
+
tiles: stableTiles,
|
|
58
73
|
cesiumIonAccessToken,
|
|
59
74
|
customProvider,
|
|
60
75
|
presets: tilePresets,
|
|
@@ -66,7 +81,9 @@ export default function ImageryLayers({
|
|
|
66
81
|
let cancelled = false;
|
|
67
82
|
const addedLayers: CesiumImageryLayer[] = [];
|
|
68
83
|
// Track layers by their intended index to maintain order with async loading
|
|
69
|
-
const layersByIndex: (CesiumImageryLayer | null)[] = new Array(
|
|
84
|
+
const layersByIndex: (CesiumImageryLayer | null)[] = new Array(stableTiles?.length || 0).fill(
|
|
85
|
+
null,
|
|
86
|
+
);
|
|
70
87
|
|
|
71
88
|
const reorderLayers = () => {
|
|
72
89
|
if (cancelled || scene.isDestroyed()) return;
|
|
@@ -91,7 +108,7 @@ export default function ImageryLayers({
|
|
|
91
108
|
scene.requestRender();
|
|
92
109
|
};
|
|
93
110
|
|
|
94
|
-
|
|
111
|
+
stableTiles?.forEach(({ id, zoomLevel, opacity, heatmap }, i) => {
|
|
95
112
|
const providerOrPromise = providers[id]?.[3];
|
|
96
113
|
if (!providerOrPromise) return;
|
|
97
114
|
|
|
@@ -117,7 +134,9 @@ export default function ImageryLayers({
|
|
|
117
134
|
};
|
|
118
135
|
|
|
119
136
|
if (providerOrPromise instanceof Promise) {
|
|
120
|
-
providerOrPromise
|
|
137
|
+
providerOrPromise
|
|
138
|
+
.then(doAdd)
|
|
139
|
+
.catch(err => console.error("Failed to load imagery provider:", err));
|
|
121
140
|
} else {
|
|
122
141
|
doAdd(providerOrPromise);
|
|
123
142
|
}
|
|
@@ -134,7 +153,9 @@ export default function ImageryLayers({
|
|
|
134
153
|
}
|
|
135
154
|
}
|
|
136
155
|
};
|
|
137
|
-
|
|
156
|
+
// Note: Using `stableTiles` to prevent re-renders when tiles reference changes but content is identical.
|
|
157
|
+
// This also stabilizes `providers` since it depends on tiles in useImageryProviders.
|
|
158
|
+
}, [providers, stableTiles, imageryLayerCollection, scene, onTilesChange]);
|
|
138
159
|
|
|
139
160
|
return null;
|
|
140
161
|
}
|