Observable not firing?

So I have a react front end for a project that is acting rather odd with an Observable.

It might be hard to visualize through just code but I was hoping someone would at least give me an idea how to troubleshoot this.

The setup I have an App buss that is responsible for making sure the 3d scene and the react app are in sync with their states. How its setup is each react useState gets set on the bus and so I am able to add callbacks and other things to the set states. Also on the bus objects there is a Observable that fires whenever the change of state is done.

One example is the “ScreenLock” functional component.

  const [isLocked, setIsLocked] = useState<boolean>(true)
  const [screenLockFade, setScreenLockFade] = useState<number>(1)  
  
  States.SetConnection(BusNames.AppBus, 'isLocked', {currentState: isLocked, set: (value:any)=>{
    console.log('screenLockFade', screenLockFade)
    if(!value && screenLockFade === 1){
      new TimedAnimation({
        duration: lockScreenTransitionDuration,
        onStep: (x: number) => {
          setScreenLockFade(1.0 - x)
        },
        onDone: () => {
          setScreenLockFade(0)
          setIsLocked(false) 
          States.AppBus.isLocked?.onChangeDoneObservable.notifyObservers(value) 
        }
      })
    }else if(value && screenLockFade === 0 ){
      new TimedAnimation({
        duration: lockScreenTransitionDuration,
        onStart: ()=>{
          setIsLocked(true)
        },
        onStep: (x: number) => {
          setScreenLockFade(x)
        },
        onDone: () => {
          setScreenLockFade(1)  
          States.AppBus.isLocked?.onChangeDoneObservable.notifyObservers(value)
        }
      })
    }    
  }})
  States.AppBus.isLocked?.onChangeDoneObservable.add((value:any)=>{
    console.log('States.AppBus.isLocked?.onChangeDoneObservable', value)
  })

This then is used in the app by calling:

States.AppBus.isLocked.set(true)

The observer and the setting of the state work perfectly, but I have a case were I am registering an addOnce callback to the States.AppBus.isLocked.onChangeDoneObservable on a button click on a different component then calling the ‘.set(true)’.

I have console logged the obs and when it fires off the ‘.notifyObservers’, but for some reason the addOnce callback is not firing even though I see it in the obs list.

const stableButtonOnClick = ()=>{
        console.log(`stableButtonOnClick`)
        const guiConnection = States.AppBus.guiLayout
        if(guiConnection && States.AppBus.isLocked){ 
             
            States.AppBus.isLocked.onChangeDoneObservable.addOnce((value)=>{
                console.log("Observer notified")
                States.ChangeScene(SceneNames[Scenes.Stables])
            })
            //console.log(States.AppBus.isLocked.onChangeDoneObservable)
            // guiConnection.set(GuiLayout.Stables)       
            States.AppBus.isLocked.set(true)
        }
    }

Everything works except the:

States.AppBus.isLocked.onChangeDoneObservable.addOnce((value)=>{
   console.log("Observer notified")
   States.ChangeScene(SceneNames[Scenes.Stables])
})

Is never seen or fires even though the notification from this comes through:

  States.AppBus.isLocked?.onChangeDoneObservable.add((value:any)=>{
    console.log('States.AppBus.isLocked?.onChangeDoneObservable', value)
  })

Anybody have any clue what could be causing this?

edit
Ohh yeah this is how the Obs is created.

public static SetConnection(busName: string, routeName: string, connection: BusConnection){
        const _states = States as any
        if(_states[busName]!== undefined && _states[busName][routeName] !== undefined){
            _states[busName][routeName] = {
                currentState: connection.currentState,
                set: connection.set,
                onChangeDoneObservable: new Observable<any>()
            }           
        }
    }

For now I added a onDone callback to the bus connection set function. That is kinda whack but it works.

Id really like to figure out why this Obs did not work though.

@brianzinn might have an idea? :thinking:

I know its kind of a loaded question, so if nobody can help that is fine. But any ideas anyone comes up with would be appreciated.

1 Like

I realise this may be a bit simple, but have you confirmed that the observable that isn’t firing is actually being registered?
I see that it’s inside an if check, you could debug to see that the if statement is working as expected or simply put a log line within the if statement to say that the callback is being registered.
Good luck with your issue.

yeah its being registered and unregistered like it fired, but then is acting like it does not exists.

I wonder if its a react state thing with a component mounting and unmounting or something.

Thanks for the idea though <3

it’s not enough code for me to see the issue. there have been a few discussions on synchronizing state across React and Babylon.js boundaries. Here is an example of subscribing to events from Observables to set state:
xmachina-semaforo/useMachina.ts at main · brianzinn/xmachina-semaforo (github.com)

You can see that I prefer to observe the events to set state rather than to publish and set state together. I think it’s just a style difference, but changes a lot the implementation details.
That code referenced above was used also for timed animations to synchronize the traffic light state to React:
xmachina semáforo (brianzinn.github.io)

2 Likes