MicheleBertoli/react-automata

componentWillTransition not working

pdkn opened this issue · 7 comments

pdkn commented

Hi, I'm using react-automata with react-native. I can't for the life of me get componentWillTransition() to fire. I've added it to the same compoent that his wrapped in withStateMachine the view is def transitioning between states. Are there any examples showing how to implement `componentWillTransition/componentDidTransition' in case I'm doing something silly? thanks

Hey @pdkn, I'm sorry to hear componentWillTransition is not working for you.
Would you be able to provide some code so that I can help?

An example of willTransition/didTransition is https://codesandbox.io/s/30x3r5vj6p.

pdkn commented

Sorry this is a bit vobose. but in this instance the 'intro' state successfully transitions to 'checkingAuth' state. Alas neither componentWillTransition or componentDidTransition are called. Looking at example above I don't spot anything wrong in the code

export interface AuthScreenProps extends NavigationScreenProps<{}> {
  appInfoStore?: AppInfoStore
  authStore?: AuthStore
  profileCollection?: ProfileCollection
  machineState?: string
  transition?: (event: string, updater?: any) => void
}

export interface AuthScreenState {
  currentState?: States
  transitionInComplete?: boolean
  transitionOutComplete?: boolean
}

@inject("appInfoStore", "authStore", "profileCollection")
@observer
class AuthScreenBase extends React.Component<AuthScreenProps, AuthScreenState> {
  constructor(props) {
    super(props)
    this.state = {
      currentState: States.INTRO,
      transitionInComplete: false,
    }
  }
  unsubscriber = null
  player: Video = null

  componentWillTransition(event) {
    console.log("EVENT", event)
    if (event === "CHECK_AUTH") {
    }
  }

  componentDidTransition(prevMachineState, event) {
    console.log("EVENT", event)
  }

  render() {
    return (
      <View style={appStyles.full}>
        <StatusBar barStyle="light-content" />
        <Wallpaper preset="cover" />
        <Video
          source={require("../../looping-bg-video.mp4")}
          ref={ref => {
            this.player = ref
          }}
          style={styles.backgroundVideo}
          rate={1}
          volume={1}
          muted={true}
          resizeMode="cover"
          repeat={true}
          key="videoBg"
        />
        <View
          style={{
            ...appStyles.full,
            backgroundColor: color.transparent,
          }}
        >
          <Screen style={{ ...appStyles.screen }} preset="fixedStack">
            <State is="intro">
              <AppRevealView onTransitionInComplete={() => this.props.transition("CHECK_AUTH")} />
            </State>

            <State is="checkingAuth">
              <CheckAuthStateView />
            </State>

            <State is="signinCTA">
              <SigninCTAView onTransitionInComplete={() => this.props.transition("CHECK_AUTH")} />
            </State>
          </Screen>
        </View>
      </View>
    )
  }
}

export const AuthScreen = withStateMachine(statechart)(AuthScreenBase)

Thanks for providing additional information, @pdkn.

I assume @inject and @observer come from mobx-react, where the documentation says:

When using both @Inject and @observer, make sure to apply them in the correct order: observer should be the inner decorator, inject the outer. There might be additional decorators in between.

So, it seems you should put withStateMachine in between them:

@inject("appInfoStore", "authStore", "profileCollection")
@withStateMachine(statechart)
@observer
class AuthScreenBase extends React.Component<AuthScreenProps, AuthScreenState> { ... }

I tried locally and it worked.
I hope this helps.

pdkn commented

Aha, wonderful. Thanks so much for quick response!

pdkn commented

@MicheleBertoli Alas might have to re-open this ;( Although above code now calls componentWillTransition and componentDidTransition successfully. The Mobx observable stores are now not updating the component. I've got 2 fixes. in dis/react-automata.es.js point the the mobx-react wrappedInstance. i.e _this.instance.current.wrappedInstance.componentWillTransition(event); or make subcomponents of the main component @Inject the stores, listen for changes and then call update methods on the main component. This prevents the subcomponent being dumb functional components (my preferred choice). Obv the patch in the dist code isn't a long-term fix but I mention it in case you can think of a clever way to make react-automata more compatible with mobx-react. Any thoughts?

Hey @pdkn, thanks for adding more information.

I'm not familiar with mobx-react and I'm not 100% sure this issue belongs here as withStateChart is a regular higher-order component. I'm also not 100% sure withStateChart should be modified to be "compatible" with MobX, or any other state management library (i.e. it should work out of the box).

Anyway, I was curious and I built a demo (which seems to work as expected):
https://codesandbox.io/s/y7pmlv6n9v

issue

Would you mind changing the code of this demo to repro your scenario where the stores are not updating the component?
I'll be happy to look into it.

pdkn commented

Thanks @MicheleBertoli that sandbox is super handy! I've modified it to a similar implementation to what I have and can confirm it's working. I better get the detective hat on and root through my codebase to see if I can find the issue. Really appreciate your help.

https://codesandbox.io/s/wov07q1157