I have this ComponentStore
@Injectable({
providedIn: 'root',
})
export class SceneGraphStore extends ComponentStore<SceneGraphState> {
private readonly sceneGraphUtils = new SceneGraphUtils();
public constructor(
public readonly sceneGraphProxy: SceneGraphProxy,
public readonly messageService: MessageService,
private readonly machineDetailStore: MachineDetailsStore,
) {
super({ isLoading: false, sceneGraph: undefined });
}
public readonly isLoading$ = this.select((state) => state.isLoading);
public readonly sceneGraph$ = this.select((state) => state.sceneGraph);
public readonly equipmentNumber$ = this.machineDetailStore.equipmentNumber$;
public readonly loadSceneGraph = this.effect(loadSceneGraph(this));
public readonly updateAxes = this.updater((state, changes: any) => {
console.log('Current State:', state); // Debugging statement
if (!state.sceneGraph) {
console.warn('Scene graph is not initialized');
return state;
}
console.log('Received Changes:', changes); // Debugging statement
const updatedSceneGraph: ObservableNode = this.sceneGraphUtils.createObservableSceneGraph(state.sceneGraph);
for (const change of changes) {
const affectedNode = this.sceneGraphUtils.getNodeByName(updatedSceneGraph, change.name!);
if (affectedNode) {
affectedNode.matrix = change.matrix!;
}
}
console.log('Updated scene graph:', updatedSceneGraph); // Debugging statement
return {
...state,
sceneGraph: updatedSceneGraph as TcNode,
};
});
// Adding a method to initialize the scene graph state
public readonly initializeSceneGraph = this.updater((state, sceneGraph: TcNode) => ({
...state,
sceneGraph,
}));
// Method to get current state for debugging
public getCurrentState(): SceneGraphState {
return this.get();
}
}
The problem is that the state within the update method updateAxes
is always undefined.
Even though I load the data correctly and is initialized.
State is always undefined. (changes
have data – it comes from the backend).
I have this effect
export const loadSceneGraph = (store: SceneGraphStore) => (equipmentNumber$: Observable<void>) =>
equipmentNumber$.pipe(
switchMap(() => store.equipmentNumber$),
filter((equipmentNumber) => equipmentNumber !== undefined),
tap(() => store.patchState({ isLoading: true })),
switchMap((equipmentNumber) =>
store.sceneGraphProxy.getSceneGraph(equipmentNumber!).pipe(
tapResponse(
(sceneGraph) => {
console.log('SceneGraph loaded:', sceneGraph); // Debugging statement
store.patchState({ sceneGraph, isLoading: false });
console.log('State after patching:', store.getCurrentState()); // Debugging statement to check state
},
(error: HttpErrorResponse) => store.messageService.showMessageAnalyticsHttpError(error),
),
finalize(() => {
store.patchState({ isLoading: false });
console.log('Final state after patching:', store.getCurrentState()); // Final state check
}),
),
),
);
According to the log, the state is initialized.
Effect is used in a component on ngOnInit
.
It fetches data from the backend and set the state.
In the component I load the data like this:
public ngOnInit() {
this.sceneGraphStore.loadSceneGraph();
this.sceneGraphStore.sceneGraph$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((sceneGraph) => {
if (sceneGraph) {
console.log('Initial SceneGraph loaded in component:', sceneGraph);
this.sceneGraphService.initializeSceneGraph(sceneGraph);
this.sceneGraph = this.sceneGraphUtils.createObservableSceneGraph(sceneGraph);
}
});
this.subscribeLiveConnection();
this.handleLiveData();
}
Also here log tells me sceneGraph Object is initialized.
But when do any updates, the store is empty, why?
The updateAxes
method is triggered when data from the backend is sent.
My guess:
The thing is updateAxes will get triggered when data from backend comes.. the data comes from Redis and is sent continously in short time (live data from machines).
Probably some race condition is the problem?
Son Hai Vu is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
This may help:
public readonly updateAxes = this.updater((state, changes: any) => {
if (!state.sceneGraph) {
console.warn('Scene graph is not initialized');
return state;
}
const updatedSceneGraph = this.sceneGraphUtils.createObservableSceneGraph(state.sceneGraph);
changes.forEach(change => {
const node = this.sceneGraphUtils.getNodeByName(updatedSceneGraph, change.name);
if (node) node.matrix = change.matrix;
});
return { ...state, sceneGraph: updatedSceneGraph as TcNode };
});
This simplified version:
- Checks if
sceneGraph
exists in the current state - Creates an updated scene graph
- Applies changes to the relevant nodes
- Returns a new state with the updated scene graph
To use this, call it like:
this.sceneGraphStore.updateAxes(changesFromBackend);
This approach should resolve the issue
1