How to make changes to GUI, using React

https://codesandbox.io/p/sandbox/codesandbox-react-tsx-forked-l45zvu

Babylonjs-hook has a sandbox, the code has a BabylonGUI function.

const BabylonGUI = () => {
  const scene = useScene()
  useEffect(() => {
    if (scene) {
      console.log('adding button')
      var advancedTexture = AdvancedDynamicTexture.CreateFullscreenUI('UI')

      var button = Button.CreateSimpleButton('but', 'Click Me')
      button.width = 0.2
      button.height = '40px'
      button.color = 'white'
      button.background = 'green'
      const observer = button.onPointerClickObservable.add((eventData) => {
        console.log('clicked eventData:', eventData)
        console.log('scene clear (GUI):', scene.clearColor.asArray().join(','))
      })!
      advancedTexture.addControl(button)

      return () => {
        button.onPointerClickObservable.remove(observer)
      }
    } else {
      console.log('scene not ready yet...')
    }
  }, [scene])
  return null
}

How can I make button.isVisible = false on a click outside BabylonGUI, for example on onButtonClick, from the DomGUI function? Even if isVisible = false is applied, the useEffect itself is not updated. I tried adding the appropriate dependencies for useEffect, but it didn’t help.

@brianzinn can you help please?

Why is useEffect not updated when the state changes?

const BabylonGUI = () => {
  const scene = useScene()
  const [buttonState, setButtonState] = useState(true)

  const hideButton = () => {
    setButtonState(false)
  }

  useEffect(() => {
    if (scene) {
      console.log('adding button')
      var advancedTexture = AdvancedDynamicTexture.CreateFullscreenUI('UI')

      var button = Button.CreateSimpleButton('but', 'Click Me')
      button.width = 0.2
      button.height = '40px'
      button.color = 'white'
      button.background = 'green'
      const observer = button.onPointerClickObservable.add((eventData) => {
        console.log('clicked eventData:', eventData)
        console.log('scene clear (GUI):', scene.clearColor.asArray().join(','))
      })!
      advancedTexture.addControl(button)
      button.isVisible = buttonState

      return () => {
        button.onPointerClickObservable.remove(observer)
      }
    } else {
      console.log('scene not ready yet...')
    }
  }, [scene, buttonState])
  return <button onClick={hideButton}>hideButton</button>
}

I solved the problem, I needed to add

 return () => {
        button.onPointerClickObservable.remove(observer)
        advancedTexture.dispose()
      }

glad you sorted it out. if you don’t want to manage the lifecycle yourself there are declarative alternatives. The declarative option handles deregistering pointer callback and texture disposing on component unmount automatically (same as your useEffect callback that you declared).

const MyComponent = () => {

  const scene = useScene();
  if (scene === null) {
    console.warn('must be inside a Scene component');
    return null;
  }

  const onButtonClick = () => {
   console.log('scene clear (GUI):', scene.clearColor.asArray().join(','))
  }
  return (
    <adtFullscreenUi name="UI">
       <babylon-button
          name="but"
          background="green"
          width={0.2}
          height="40px"
          cornerRadius={10}
          onPointerDownObservable={onButtonClick}
        >
          <textBlock
            name="but-text"
            text="Click Me"
            fontSize={28}
            fontStyle="bold"
            color="white"
          />
    </babylon-button>
   </adtFullscreenUi>
  )
}

You can see that CreateFullscreenUI static method has been implemented. I haven’t implemented other ones like “CreateSimpleButton”. There’s not a lot in there anyway. When you try to mix JSX from the DOM renderer and the one for babylon.js in the same component then you will end up with issues - That’s when state management would be able to solve. I think declarative GUI is one of the strong points of using the library - especially with hot reloading.

2 Likes

Thank you very much, I will rewrite my DOM following your example