React-native-router-flux: Navigation actions and MobX based app

Created on 23 Jul 2017  ·  21Comments  ·  Source: aksonov/react-native-router-flux

First and foremost I want to thank you for this project. As a beginner with RN I've stumbled upon react-navigation and was awfully confused not even mentioning it doesn't work well in some scenarios.

Anyway, I want to ask what would be the best pattern for invoking navigation actions outside of components? Initially, we are rendering simple Loading component with a picture and preloading assets and also verifying authentication. Based on auth state we want to navigate to the different scenes. We are also using MobX for app stores.

export default observer(function Main() {
  if (stores.preloadStore.loading) {
    return <Loading />
  }

  return (
    <Provider {...stores}>
      <Router>
        <Scene tabs navTransparent key="main">
          <Scene hideNavBar key="load" component={LoadingScene} />
          <Scene hideNavBar key="auth" component={AuthScene} />
          <Scene hideNavBar key="menu" component={MenuScene} />
        </Scene>
      </Router>
    </Provider>
  )
})

Then we have this simple autorun. The problem with this solution is that since Actions.auth() is also MobX, this autorun will also observe changes in a navigationStore and if we wouldn't call dispose here, it would end up with endless loop since the navigation action causes change to the navigationStore.

const disposeRedirect = autorun(() => {
  if (!authStore.isInitializing && !preloadStore.loading) {
    if (authStore.isAuthenticated) {
      Actions.menu()
      disposeRedirect()
    } else {
      Actions.auth()
    }
  }
})

Generally, it looks like a bad idea to cause navigation changes within stores. Am I missing something here? Perhaps some more declarative approach from within the component?

help wanted

Most helpful comment

Where is the ExampleMobX demo project? I want to learn how to combo RNRF v4 and Mobx work together, thanks very much.

All 21 comments

Good question, could you please give me a link to that project or even better, could you submit PR with this demo (with simple login/auth/loading screens and some fake auth), so I could include it as mobX example? We could name it as ExampleMobX project.

I will try to prepare some MobX demo (it could be very simple at the beginning) to demonstrate best-practices with MobX

@aksonov I am not sure what are you asking me for. I've already shown relevant code except for store itself, but that's just a couple of observable properties, nothing special about it.

You are saying that only way of using within MobX app is to be careful about disposing of autorun? :) That feels like a rather big source of problems to me.

No, navigation actions should not be done within autorun - it is not intuitive and difficult to debug way. Correct way is to use on(onEnter) and success, failure properties (more correct analog of v3 Switch statement)

Ok, I think I've got some partial solution. This essentially works for the "load" scene where it can decide which way to go based on auth. However, I am struggling with redirecting to "menu" scene after the moment user gets authenticated. Apparently onEnter of the "auth" scene is not rerun when state changes.

function Main() {
  if (stores.preloadStore.loading) {
    return <LoadingScene />
  }

  const guardAuth = () => {
    const { authStore } = stores
    if (authStore.isInitializing) {
      return false
    }
    return authStore.isAuthenticated
  }

  return (
    <Provider {...stores}>
      <Router>
        <Scene key="main">
          <Scene key="load" component={LoadingScene}  initial on={guardAuth} success="menu" failure="auth" />
          <Scene key="auth" component={AuthScene} on={guardAuth} success="menu" />
          <Scene key="menu" component={MenuScene} />
        </Scene>
      </Router>
    </Provider>
  )
}

Edit: Updated example to use string for success/failure

Use string, success='menu'

25 июля 2017 г., в 22:52, Daniel K. notifications@github.com написал(а):

Ok, I think I've got some partial solution. This essentially works for the "load" scene where it can decide which way to go based on auth. However, I am struggling with redirecting to "menu" scene after the moment user gets authenticated. Apparently onEnter of the "auth" scene is not rerun when state changes.

function Main() {
if (stores.preloadStore.loading) {
return
}

const guardAuth = () => {
const { authStore } = stores
if (authStore.isInitializing) {
return false
}
return authStore.isAuthenticated
}

return (








)
}
There is also a small bummer that I cannot do directly success={Actions.menu} but need to wrap into a function. Not sure why is that, no error is popping there.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.

Ok, that's nice feature, although undocumented ;)

The main problem still remains though. Where to do navigation when a user gets authenticated? I guess that only viable solution is autorun in componentDidMount of AuthScene. It's not very nice, but I am unable to come up with anything else.

Where is the ExampleMobX demo project? I want to learn how to combo RNRF v4 and Mobx work together, thanks very much.

@aksonov Any other idea how to solve the problem at hand?

I think that things would great if on/onEntry/onExit would actually be automatic observers or even have a separate property for that to run success/failure based on that.

Maybe I am missing something out here, but due to the fact, that with MobX it's not about re-rendering whole component tree, it shouldn't be probably build around events on a particular scene/route. Those are not executed when something in MobX store changes. It could be simple autorun that is setup before entering scene and disposed on exiting it.

@FredyC It seems MobX observables/observer/autorun concept is a little bit different from redux-like react-navigation immutable state. onEnter allows to decide where to go but it should not be re-run because app could be already in different state (screen). And yes, you may add simple autoruns to return back to login screen once auth flag is changed easily.

@scriptfans and others
It is difficult and time consuming to create demo from scratch (like create loading/auth screen/main screen/logout/menu/etc, find needed icons, etc). If someone could share simple demo I could help to improve it to work with MobX. Feel free to submit PR or you could create own repo for this if you want to be maintainer.

@aksonov But autorun is what I had initially and it means I need to be careful about disposing it otherwise I might end up with endless loop. Not even mentioning it's ugly as hell and goes against philosophy of this package, doesn't it? I mean navigation logic in one place.

I can imagine something like this which would use autorun underneath that would be setup when you enter the scene and disposed when you leave it. Whenever observable yields a change, the result of it would use success/failure as usual. Does that make a sense?

<Scene observe={() => user.isAuthenticated} success="menu" failure="login" />

It is interesting idea. But we can't dispose it when leave that scene - than observing will not happen. And now image several 'observe' Scenes and then could conflict each other or make infinite loop, etc... Need to think about it more. For now let's make some MobX demo but I really need help for this.

Yea, it needs some more thinking through. Maybe if it would work on parent scenes too and then you would have a nice declarative guard that would go to login whenever user loses authentication.

If it would be on a nested scene ten auto dispose would keep logic sane and essentially just used to declaratively say where to go next. For example, you would change currentItem in your store and guard on the scene would catch that and redirect to a detail scene. Something like that...

Anyway, I am afraid I cannot help you with the demo, because I simply don't understand how to do it yet. Using autorun in componentDidMount feels so awfully dirty... And the onEnter/onExit does not really work well with MobX based store. I am clueless how it's intended to work really.

Could you make demo with simple Actions.SCENE calls from componentDidMount() for 'loading' scene ? After that I will replace it with mobx logic.

@aksonov I change a demo to use RNRF and Mobx, but I am not sure it use the correct way. Can you give me some advice? ShiWuPai

@keith527 Great, do you have English interface? I'm not sure I could understand it with Chineese...

@aksonov I am so sorry, This api is from a Chinese company, so....I am not sure what's I can help you.

Just finished some basic conversion of nice starter kit with auth example (without dynamic recipes retrieval from firebase) to RNRF v4: https://github.com/aksonov/react-native-starter-app

Sorry, Redux was replaced for Mobx for great simplicity...

Any PR about new features demonstrated within that starter kit (on/success/failure transitions) is welcome.

@aksonov what if I want to track the previous screen? How would that look like with MobX?

@aksonov is there anyway that we can check whether the drawer is open or not?

@radha-bacancy Just check navigation state

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jgibbons picture jgibbons  ·  3Comments

fgrs picture fgrs  ·  3Comments

xnog picture xnog  ·  3Comments

booboothefool picture booboothefool  ·  3Comments

basdvries picture basdvries  ·  3Comments