Skip to content

Instantly share code, notes, and snippets.

@knowbody
Last active July 17, 2023 10:14
Show Gist options
  • Star 67 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
  • Save knowbody/ce483742a1761658b767428a0ed35147 to your computer and use it in GitHub Desktop.
Save knowbody/ce483742a1761658b767428a0ed35147 to your computer and use it in GitHub Desktop.
My exponent's ex-navigation docs/thoughts

Exponent - ex-navigation

This is for now, for my personal use only, things might not be correctly explained here. For the official docs please check: https://github.com/exponentjs/ex-navigation/blob/master/README.md

Navigation bar configuration

On every screen you can use the built-in navigation bar, you can add a title, left button, right button or change navigation bar’s style. All you need to do is pass appropriate params to navigationBar in the route configuration:

import React, { Component } from 'react';

class Foo extends Component {
  static route = {
    navigationBar: {
      title: 'Assignments',
      backgroundColor: 'tomato',
      elevation: 2,
      renderLeft: () => <MenuButton />,
    },
  };

  render() { /* … */ };
}

How can I slide my view from bottom up (transition) from one screen to the other?

You simply need to add styles to your route configuration in the Component that you are pushing onto StackNavigation:

import React, { Component } from 'react';
import { NavigationStyles } from '@exponent/ex-navigation';

class Foo extends Component {
  static route = {
    styles: {
      ...NavigationStyles.SlideVertical,
    },
  };

  render() { /* … */ };
}

StackNavigation default config

You can set a default config for StackNavigation by using defaultRouteConfig property:

import { StackNavigation, NavigationStyles } from '@exponent/ex-navigation';
import Router from '../navigation/Router';

<StackNavigation
  id="master"
  defaultRouteConfig={{
    styles: {
      ...NavigationStyles.SlideVertical,
    },
    navigationBar: {
      backgroundColor: '#fff',
      tintColor: 'tomato',
    },
  }}
  initialRoute={Router.getRoute('about')}
/>

Having these set like above will make each screen to slide vertically, have a white background color, and tomato tint color. But you can obviously override these setting within your particular route config.

How to disable "slide screen to go back" (the native behaviour of pop()ing the view if you swipe from left to right or top to bottom)

In order to disable it you need to pass a gesture: null to styles in route configuration:

import React, { Component } from 'react';
import { NavigationStyles } from '@exponent/ex-navigation';

class Foo extends Component {
  static route = {
    styles: {
      gestures: null,
    },
  };

  render() { /* … */ };
}

Modals

I found it as a good practice to always have the very high level navigator in my app. I usually use StackNavigation. And then have another navigator under it which is in use most of the times. Then whenever I need to push the modal (i.e. Login screen, Menu, etc.) I push it on the top level (master) StackNavigation.

Here is an example of my main.js :

/* ... */

return (
  <Provider store={configureStore()}>
    <View style={styles.container}>
      <NavigationProvider router={Router}>
        <StackNavigation
          id="master"
          initialRoute={Router.getRoute('app', { notification })}
          defaultRouteConfig={{
            styles: {
              ...NavigationStyles.SlideVertical,
            },
          }}
        />
      </NavigationProvider>

      {Platform.OS === 'ios' && <StatusBar barStyle="light-content" animated />}
      {Platform.OS === 'android' && <View style={styles.statusBarUnderlay} />}
    </View>
  </Provider>
);

And then my app route can be a DrawerNavigation or StackNavigation or whatever navigator you want it to be, but you can always push the modal onto master.

Here is how you can get any navigator from where you have naviagtion available in your props (if you don't, you can use withNavigation() HOC, or pass it down as a prop from the component where you have it available).

Use getNavigator():

this.props.navigation.getNaviagtor('master');

Reset/modify the navigation stack (history)

Sometimes you might want to reset or modify your navigation stack. For example I have an app where user needs to fill up a questionaire, and after is presented with some results. At this point I don't want the user to be able to go back to the questionaire anymore, instead the user can click DONE, and go back to the route foo (which is the route from which the user start the questonaire from). At this point the only thing I want in my navigation stack is the route foo. You can achieve that using immediatelyResetStack() which is a function available from the navigator object. Here is an example usage:

const rootNavigator = this.props.navigation.getNavigator('root');

return (
  <TouchableOpacity 
    onPress={() => 
      rootNavigator.immediatelyResetStack([Router.getRoute('foo')], 0)
    }
  >
    <Text>Done!</Text>
  </TouchableOpacity>
);

the function takes two arguments:

  • routes - an array of routes
  • index - index of a route which navigation stack should be reset to
@sibelius
Copy link

this gist is very useful, we should incorporate it do ex-navigation docs \o/

@cesar
Copy link

cesar commented Nov 1, 2016

This is great help! Thanks!

@f0rr0
Copy link

f0rr0 commented Nov 18, 2016

You're a lifesaver. One thing I found out was that with immediatelyResetStack, the route transition animations don't work. Perhaps that's why the name. This kind of makes it unusable for the purpose of resetting the stack :/ I can't figure out how to transition to a route and then clear all previous routes in the stack.

@vonovak
Copy link

vonovak commented Nov 27, 2016

@knowbody how do you handle the android back button? The trouble with displaying modal this way is that it changes the active navigator, and that breaks the back button - and also breaks navigation from out of components, such as

import { NavigationActions } from '@exponent/ex-navigation'
import Store from '../state/Store';
import Router from './Router'

export default function goHome() {
  let navigatorUID = Store.getState().navigation.currentNavigatorUID;
  Store.dispatch(NavigationActions.push(navigatorUID, Router.getRoute('home')))
}

because currentNavigatorUID will be set to the master one after dismissing a modal.

@knowbody
Copy link
Author

@vonovak it seems like a back button works fine in my app... but I will look into it and get back to you, thanks for the feedback

@leocavalcante
Copy link

Just fix the first example, you are passing the params directly on the route object, not in a navigationBar object.

@knowbody
Copy link
Author

@leocavalcante good catch thanks! fixed

@vonovak
Copy link

vonovak commented Nov 30, 2016

@knowbody I have filed an issue with a gif that shows exactly what my problem is. Would appreciate any input.

@vonovak
Copy link

vonovak commented Dec 6, 2016

another good source on information about modals is https://github.com/brentvatne/movieapp/tree/master/src/navigation

@chetankothari
Copy link

@knowbody Thanks for the amazing gist. This helped me solve some of my major problems. But however I am stuck with one problem. I have a similar scenario as mentioned in the Reset/Modify history section of the gist and I am using the Modals style for the same. So the way I present the questionaire here is push a StackNavigation on the root/master stack. Everything works fine except for one thing and that is at the end when the user is done. I would like to pop the modal and go back to the master stack. I will be able to do it with the Done button and by overriding the NavigationBar Back Button but however I am concerned about the Android Back Button. How do you suggest this be handled here.

@satya164
Copy link

@chetankothari you can add a listener for back button and return false there. Sucks to have same logic in 2 places, but it's the only way.

@cyprusglobe
Copy link

@satya14 you should post an example repo :)

@mattcleary55
Copy link

mattcleary55 commented Dec 29, 2016

Hey guys and @knowbody, this is awesome.

A question please!

In my tabNavigation, if my feed tab is already selected and a user clicks on it again, it will navigate to a 'New Post' screen. I've added:

   styles: {
     ...NavigationStyles.SlideVertical,
   },
 };

to the newPost screen and it slides up from the bottom just fine.

From there user can make a new post and type in any text they like for the post, they click 'Next' and then I push on a new screen that comes in from the right. This is so they can tag topics etc. When the user is finished, they click the done button. I want the screen to then slide back down. Is this there anyway I can do this? Right now I can only get it to slide in from the left by popping or replacing, which doesn't feel right at all.

Any idea guys?

Thanks!

@jsdario
Copy link

jsdario commented Jan 12, 2017

How can we change the direction of sliding? I have been reading the source https://github.com/exponent/ex-navigation/blob/master/src/ExNavigationStyles.js, but it is being hard. Anyone did this before? There seem to be several modes possible already.

@sibelius
Copy link

let's add all this recipes here: https://github.com/sibelius/ex-navigation-recipes

@ranjeev75
Copy link

ranjeev75 commented Jan 27, 2017

How can you override the backgroundColor of the scenes in defaultRouteConfig to white to transparent?

@yeso126
Copy link

yeso126 commented Feb 2, 2017

Im getting getNavigatior is not a function, any help? im passing @withNavigation to the component

@mattmcdonald-uk
Copy link

@yeso126 - getNavigatior is a typo in the example, it's meant to be getNavigator

@qrobin
Copy link

qrobin commented Feb 19, 2017

Thank you for sharing this.

@annelorraineuy
Copy link

I noticed that isFocused is a hit or miss. Is there a workaround for finding out consistently if the screen is in focus?

@roshangm1
Copy link

The same issue as @annelorraineuy

@mativs
Copy link

mativs commented May 10, 2017

Hey thanks!! It is very useful. A small correction this line

this.props.navigation.getNaviagtor('master');

should be

this.props.navigation.getNavigator('master');

😄

Thanks again!!

Edited: It was already mentioned ... sorry

@kay-es
Copy link

kay-es commented Nov 6, 2017

Hey,
i want to use this modal style but I always get an error while starting the app which says:
Invariant Violation: Navigator does not exist

My main.js looks up to the parameters exactly like the example above and my route "app" looks like this.

`render() {

return (
  <NavigationProvider router={Router}>
      <StackNavigation
        id='app'
        initialRoute='home'
        defaultRouteConfig={{
          navigationBar: {
            /* options and renderings here */
          }
        }}
      />
  </NavigationProvider>
);

}`

Could anyone tell me what I'm doing wrong? :/
If I remove the StackNavigation from the App, it works and doesn't crash.

best regards
kay

SOLVED: Just had to remove the NavigationProvider in the app screen because its already provided by the main.js.

@BhanuSagar1
Copy link

hello guyz..I am new to react native need some help. I am using expo/ex-navigation for a react native mobile application.In that i want to hide tabbar on a particular screen .For example when i navigate home to another screen In that another screen i dont want tabbar how can we do that...actually when i am navigationg to another screen it was navigating in same tab so that tabbar is sticky in bottom..I dont want that tabbar on navigation..Help me friends

I tried this this.props.navigation.getNavigator('master').push(Router.getRoute('postDetail', {id}));
OutPut: Navigator Does Not Exist
what is getNavigator('master') ???

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment