Skip to content

Commit cbd0057

Browse files
Chau TranChau Tran
Chau Tran
authored and
Chau Tran
committed
fix(core): use behavior subject for parent
1 parent 4340998 commit cbd0057

File tree

9 files changed

+20
-26
lines changed

9 files changed

+20
-26
lines changed

libs/angular-three/src/lib/renderer/renderer.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,10 @@ import {
88
effect,
99
getDebugNode,
1010
inject,
11-
signal,
12-
untracked,
1311
type Renderer2,
1412
type RendererType2,
1513
} from '@angular/core';
14+
import { BehaviorSubject } from 'rxjs';
1615
import { NGT_CATALOGUE } from '../di/catalogue';
1716
import type { NgtInjectedRef } from '../di/ref';
1817
import { NgtStore } from '../stores/store';
@@ -117,7 +116,7 @@ export class NgtRenderer implements Renderer2 {
117116
{ __ngt_renderer__: { rawValue: undefined } },
118117
// NOTE: we assign this manually to a raw value node
119118
// because we say it is a 'three' node but we're not using prepare()
120-
{ __ngt__: { isRaw: true, parent: signal(null) } }
119+
{ __ngt__: { isRaw: true, parent: new BehaviorSubject(null) } }
121120
)
122121
);
123122
}
@@ -243,7 +242,7 @@ export class NgtRenderer implements Renderer2 {
243242
// if both are three instances, straightforward case
244243
if (pRS[NgtRendererClassId.type] === 'three' && cRS[NgtRendererClassId.type] === 'three') {
245244
// if child already attached to a parent, skip
246-
if (getLocalState(newChild).parent && untracked(getLocalState(newChild).parent)) return;
245+
if (getLocalState(newChild).parent?.value) return;
247246
// attach THREE child
248247
attachThreeChild(parent, newChild);
249248
// here, we handle the special case of if the parent has a compoundParent, which means this child is part of a compound parent template
@@ -284,7 +283,7 @@ export class NgtRenderer implements Renderer2 {
284283

285284
const shouldFindGrandparentInstance =
286285
// if child is three but haven't been attached to a parent yet
287-
(cRS[NgtRendererClassId.type] === 'three' && !untracked(getLocalState(newChild).parent)) ||
286+
(cRS[NgtRendererClassId.type] === 'three' && !getLocalState(newChild).parent.value) ||
288287
// or both parent and child are DOM elements
289288
// or they are compound AND haven't had a THREE instance yet
290289
((pRS[NgtRendererClassId.type] === 'dom' ||

libs/angular-three/src/lib/renderer/store.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ export class NgtRendererStore {
221221
return;
222222
}
223223

224-
const parent = getLocalState(node).parent() || rS[NgtRendererClassId.parent];
224+
const parent = getLocalState(node).parent?.value || rS[NgtRendererClassId.parent];
225225

226226
// [rawValue]
227227
if (getLocalState(node).isRaw && name === SPECIAL_PROPERTIES.VALUE) {

libs/angular-three/src/lib/renderer/utils.ts

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,7 @@ export function attachThreeChild(parent: NgtInstanceNode, child: NgtInstanceNode
7575
// attach
7676
if (cLS.isRaw) {
7777
if (cLS.parent) {
78-
queueMicrotask(() => {
79-
cLS.parent.set(parent);
80-
});
78+
cLS.parent.next(parent);
8179
}
8280
// at this point we don't have rawValue yet, so we bail and wait until the Renderer recalls attach
8381
if (child.__ngt_renderer__[NgtRendererClassId.rawValue] === undefined) return;
@@ -96,9 +94,7 @@ export function attachThreeChild(parent: NgtInstanceNode, child: NgtInstanceNode
9694
pLS.add(child, added ? 'objects' : 'nonObjects');
9795

9896
if (cLS.parent) {
99-
queueMicrotask(() => {
100-
cLS.parent.set(parent);
101-
});
97+
cLS.parent.next(parent);
10298
}
10399

104100
if (cLS.afterAttach) cLS.afterAttach.emit({ parent, node: child });
@@ -112,9 +108,7 @@ export function removeThreeChild(parent: NgtInstanceNode, child: NgtInstanceNode
112108
const cLS = getLocalState(child);
113109

114110
// clear parent ref
115-
queueMicrotask(() => {
116-
cLS.parent?.set(null);
117-
});
111+
cLS.parent?.next(null);
118112

119113
// remove child from parent
120114
if (untracked(pLS.objects)) pLS.remove(child, 'objects');

libs/angular-three/src/lib/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { ElementRef, EventEmitter, WritableSignal } from '@angular/core';
2+
import { BehaviorSubject } from 'rxjs';
23
import * as THREE from 'three';
34
import type { NgtSignalStore } from './stores/signal.store';
45
import { NgtObject3DNode } from './three-types';
@@ -255,7 +256,7 @@ export type NgtInstanceLocalState = {
255256
// native props signal
256257
nativeProps: NgtSignalStore<NgtAnyRecord>;
257258
// parent based on attach three instance
258-
parent: WritableSignal<NgtInstanceNode | null>;
259+
parent: BehaviorSubject<NgtInstanceNode | null>;
259260
// if this THREE instance is a ngt-primitive
260261
primitive?: boolean;
261262
// if this THREE object has any events bound to it

libs/angular-three/src/lib/utils/apply-props.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { untracked } from '@angular/core';
21
import * as THREE from 'three';
32
import type { NgtAnyRecord, NgtInstanceNode } from '../types';
43
import { getLocalState, invalidateInstance } from './instance';
@@ -112,7 +111,7 @@ export function applyProps(instance: NgtInstanceNode, props: NgtAnyRecord): NgtI
112111
}
113112

114113
const instanceHandlers = localState.eventCount;
115-
const parent = localState.parent ? untracked(localState.parent) : null;
114+
const parent = localState.parent?.value;
116115

117116
if (parent && rootState.internal && instance['raycast'] && instanceHandlers !== localState.eventCount) {
118117
// Pre-emptively remove the instance from the interaction manager

libs/angular-three/src/lib/utils/instance.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { signal, untracked } from '@angular/core';
2+
import { BehaviorSubject } from 'rxjs';
23
import { NgtSignalStore } from '../stores/signal.store';
34
import type { NgtAnyRecord, NgtInstanceLocalState, NgtInstanceNode } from '../types';
45
import { checkUpdate } from './update';
@@ -32,7 +33,7 @@ export function prepare<TInstance extends object = NgtAnyRecord>(
3233
instance.__ngt__ = {
3334
previousAttach: null,
3435
store: null,
35-
parent: signal(null),
36+
parent: new BehaviorSubject(null),
3637
memoized: {},
3738
eventCount: 0,
3839
handlers: {},
@@ -51,13 +52,13 @@ export function prepare<TInstance extends object = NgtAnyRecord>(
5152
} else {
5253
instance.__ngt__[type].update((prev) => [...prev, object]);
5354
}
54-
notifyAncestors(untracked(instance.__ngt__.parent));
55+
notifyAncestors(instance.__ngt__.parent.value);
5556
});
5657
},
5758
remove: (object, type) => {
5859
queueMicrotask(() => {
5960
instance.__ngt__[type].update((prev) => prev.filter((o) => o !== object));
60-
notifyAncestors(untracked(instance.__ngt__.parent));
61+
notifyAncestors(instance.__ngt__.parent.value);
6162
});
6263
},
6364
...rest,
@@ -72,5 +73,5 @@ function notifyAncestors(instance: NgtInstanceNode | null) {
7273
const localState = getLocalState(instance);
7374
if (localState.objects) localState.objects.update((prev) => prev);
7475
if (localState.nonObjects) localState.nonObjects.update((prev) => prev);
75-
notifyAncestors(untracked(localState.parent));
76+
notifyAncestors(localState.parent.value);
7677
}

libs/soba/materials/src/mesh-reflector-material/mesh-reflector-material.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ export class NgtsMeshReflectorMaterial extends NgtSignalStore<NgtsMeshReflectorM
261261

262262
#onBeforeRender(state: NgtRenderState) {
263263
if (!this.materialRef.nativeElement) return;
264-
const parent = getLocalState(this.materialRef.nativeElement).parent();
264+
const parent = getLocalState(this.materialRef.nativeElement).parent?.value;
265265
if (!parent) return;
266266

267267
const { gl, scene } = state;
@@ -288,7 +288,7 @@ export class NgtsMeshReflectorMaterial extends NgtSignalStore<NgtsMeshReflectorM
288288
}
289289

290290
#beforeRender(state: NgtRenderState) {
291-
const parent = getLocalState(this.materialRef.nativeElement).parent();
291+
const parent = getLocalState(this.materialRef.nativeElement).parent?.value;
292292
if (!parent) return;
293293

294294
const { camera } = state;

libs/soba/materials/src/mesh-refraction-material/mesh-refraction-material.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ export class NgtsMeshRefractionMaterial extends NgtSignalStore<NgtsMeshRefractio
137137
effect(() => {
138138
const material = this.materialRef.nativeElement;
139139
if (!material) return;
140-
const geometry = getLocalState(material).parent()?.geometry;
140+
const geometry = getLocalState(material).parent?.value?.geometry;
141141
if (geometry) {
142142
(material as any).bvh = new MeshBVHUniformStruct();
143143
(material as any).bvh.updateFrom(

libs/soba/materials/src/mesh-transmission-material/mesh-transmission-material.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ export class NgtsMeshTranmissionMaterial extends NgtSignalStore<NgtsMeshTranmiss
209209
this.materialRef.nativeElement.time = state.clock.getElapsedTime();
210210
// Render only if the buffer matches the built-in and no transmission sampler is set
211211
if (this.materialRef.nativeElement.buffer === this.fboMainRef().texture && !transmissionSampler) {
212-
parent = getLocalState(this.materialRef.nativeElement).parent() as THREE.Object3D;
212+
parent = getLocalState(this.materialRef.nativeElement).parent?.value as THREE.Object3D;
213213
if (parent) {
214214
// Save defaults
215215
oldTone = state.gl.toneMapping;

0 commit comments

Comments
 (0)