Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Feb 15, 2019. It is now read-only.
/ex-navigationPublic archive

Route-centric navigation for React Native

NotificationsYou must be signed in to change notification settings

expo/ex-navigation

Repository files navigation

Please use"react-navigation", orother alternatives instead.


ExNavigation

A route-centric, batteries-included navigation library for Expo andReact Native that works seamlessly on Android and iOS.

A few of our favorite features

  • Android back button handling (it just works, no need to do anything)
  • Tab bar navigation
  • Drawer navigation
  • Sliding tab navigation
  • Optional blurred translucent backgrounds in navigation and tab bar on iOS
  • Alert bars
  • Declarative configuration co-located with your routes
  • Typed with Flow

Help / Support / Questions

We don't provide any realtime support for ExNavigation questions. If youjoin the Expo Slack and ask a question there, we will direct you tothis section of the README. We suggest the following resources:

Installation

As of version 1.9.0, ExNavigation only supports React Native versions >=0.36.0 due to changes to the css-layout algorithm in React Native core.

  • npm i @expo/ex-navigation babel-preset-react-native-stage-0 --save
  • Change your.babelrc (if you have one, if not, then create one):
{  "presets": ["react-native-stage-0/decorator-support"]}

Note: Comprehensive documentation is coming soon! For now, check out the example project inexample/. This lib is very much a work in progress.

How to run the example project

or use this link in your mobile phone:https://expo.io/@community/ex-navigation-example

How is this different from what is built into React Native?

NavigationExperimental ships with React Native, it is powerful andflexible, and that comes at the cost of exposing some internals to theapp developer. ExNavigation is built on top ofNavigationExperimentalwith the aim of providing a more feature-rich out of the box experience.

A minimal navigation set up

To give you an idea of what the required pieces of are, the followingincludes only the minimal code necessary to get ExNavigation working.

importReactfrom'react';import{AppRegistry,Text,View,}from'react-native';/** * If you're using Expo, uncomment the line below to import Exponent * BEFORE importing `@expo/ex-navigation`. This sets the status bar * offsets properly. */// import Expo from 'expo';import{createRouter,NavigationProvider,StackNavigation,}from'@expo/ex-navigation';/**  * This is where we map route names to route components. Any React  * component can be a route, it only needs to have a static `route`  * property defined on it, as in HomeScreen below  */constRouter=createRouter(()=>({home:()=>HomeScreen,}));classAppextendsReact.Component{render(){/**      * NavigationProvider is only needed at the top level of the app,      * similar to react-redux's Provider component. It passes down      * navigation objects and functions through context to children.      *      * StackNavigation represents a single stack of screens, you can      * think of a stack like a stack of playing cards, and each time      * you add a screen it slides in on top. Stacks can contain      * other stacks, for example if you have a tab bar, each of the      * tabs has its own individual stack. This is where the playing      * card analogy falls apart, but it's still useful when thinking      * of individual stacks.      */return(<NavigationProviderrouter={Router}><StackNavigationinitialRoute={Router.getRoute('home')}/></NavigationProvider>);}}classHomeScreenextendsReact.Component{/**    * This is where we can define any route configuration for this    * screen. For example, in addition to the navigationBar title we    * could add backgroundColor.    */staticroute={navigationBar:{title:'Home',}}render(){return(<Viewstyle={{alignItems:'center',justifyContent:'center',flex:1}}><Text>HomeScreen!</Text></View>)}}AppRegistry.registerComponent('main',()=>App);

Push and popping routes

 const Router = createRouter(() => ({   home: () => HomeScreen,+  about: () => AboutScreen, })); class HomeScreen extends React.Component {    render() {     return (       <View style={{alignItems: 'center', justifyContent: 'center', flex: 1}}>         <Text>HomeScreen!</Text>+        <Text onPress={this._goToAbout}>+          Push about route+        </Text>       </View>     )   }++  _goToAbout = () => {+    this.props.navigator.push(Router.getRoute('about'));+  } }+ class AboutScreen extends React.Component {+  static route = {+    navigationBar: {+      title: 'About',+    }+  }++  render() {+    return (+      <View style={{alignItems: 'center', justifyContent: 'center', flex: 1}}>+        <Text>AboutScreen!</Text>+        <Text onPress={this._goBackHome}>+          Go back home+        </Text>+      </View>+    )+  }++  _goBackHome = () => {+    this.props.navigator.pop();+  }+}

In the above example you will see that wepush andpop routes to andfrom the stack by calling those functions on thenavigator prop. Thisis a prop that is passed into all components that you registered withthe router. If you need to access thenavigator on a component thatis not a route, you can either pass it in manually from your routecomponent or usewithNavigation as a decorator on the component:

importReactfrom'react';import{Text}from'react-native';import{withNavigation}from'@expo/ex-navigation';@withNavigationclassBackButtonextendsReact.Component{render(){return<TextonPress={this._goBack}>Go back</Text>}_goBack=()=>{if(this.props.navigator.getCurrentIndex()>0){this.props.navigator.pop();}}}

Alternatively, rather than importingRouter each time, you may pass theroute's name directly:

_goToAbout = () => {-  this.props.navigator.push(Router.getRoute('about'));+  this.props.navigator.push('about');}

… bearing in mind you will loose the ability to type check the route (if usingFlow).

Passing params to a route

  class HomeScreen extends React.Component {   _goToAbout = () => {-    this.props.navigator.push(Router.getRoute('about'));+    this.props.navigator.push(Router.getRoute('about', {name: 'Brent'}));   } } class AboutScreen extends React.Component {   static route = {     navigationBar: {-      title: 'About',+      title(params) {+        return `Greeting for ${params.name}`;+      },     }   }   render() {     return (       <View style={{alignItems: 'center', justifyContent: 'center', flex: 1}}>-        <Text>AboutScreen!</Text>+        <Text>AboutScreen! Hello {this.props.route.params.name}</Text>         <Text onPress={this._goBackHome}>           Go back home         </Text>

Updating route params

Sometimes you don't have all of the data that you need to set thenavigation bar title when you mount the route - for example, if younavigate to a user profile screen by user id and need to fetch theprofile data before you know what the name is. In this case,one solution is to use theupdateCurrentRouteParams function availableonStackNavigation navigators.

 class AboutScreen extends React.Component {   static route = {     navigationBar: {       title(params) {-        return `Greeting for ${params.name}`;+        if (typeof params.isCool === 'undefined') {+          return '';+        }++        return params.isCool ? `Hey cool person!` : `zzz`;       },     }   }+  componentDidMount() {+    setTimeout(() => {+      this.props.navigator.updateCurrentRouteParams({+        isCool: this.props.route.params.name === 'Brent'+      })+    }, 1000);+  }+

Make navigation bar buttons update based on route or app state

See the following example for details on how to connect your buttons tothe navigator or Redux to perform actions:https://github.com/brentvatne/ex-navigation-conditional-buttons-example

StackNavigation actions

As you saw above, you canpush andpop routes. The following is afull list of functions that can be called on StackNavigation navigators.

  • push: add a route to the top of the stack
  • pop(n): remove n routes from the top of the stack, defaults to 1
  • popToTop: remove all but the first route from the stack
  • replace: replace the current route with a given route
  • showLocalAlert: show an alert bar with given text and styles
  • hideLocalAlert: hide an active alert bar
  • immediatelyResetStack: reset the current stack to the given stack
  • updateCurrentRouteParams: update route params as in the above example

Working with the navigation bar

The navigation bar configuration exposes a set of useful options thatshould allow you to do most things that you will want to do with it.

You specify the configuration for thenavigationBar on the routecomponent, or on aStackNavigation component.

On a route component

When you configure thenavigationBar on a route component, theconfiguration only applies to that specific component. This isusually useful for specifying the title or components to renderon the left or right of the title.

classHomeScreenextendsReact.Component{_goToAbout=()=>{this.props.navigator.push(Router.getRoute('about',{name:'Brent'}));}}classAboutScreenextendsReact.Component{staticroute={navigationBar:{title:'Title goes here',renderRight:(route,props)=><SignOutButtonname={route.params.name}/>}}// ...} @connect()classSignOutButtonextendsReact.Component{render(){return(<TouchableOpacityonPress={this.props.dispatch(Actions.signOut())}><Text>Sign out{this.props.name}</Text></TouchableOpacity>);}}

On StackNavigation

You can configure thedefaultRouteConfig for all routes within aStackNavigation to save you needing to specify properties likethenavigationBarbackgroundColor andtintColor (color touse for the title and back button or drawer menu hamburger button).

classAppextendsReact.Component{render(){return(<NavigationProviderrouter={Router}><StackNavigationdefaultRouteConfig={{navigationBar:{backgroundColor:'#000',tintColor:'#fff',}}}initialRoute={Router.getRoute('home')}/></NavigationProvider>);}}

navigationBar properties

  • title - a string or a function that returns a string. The function is provided with the route params as the first argument.
  • titleStyle - Text.propTypes.style object to use for the title.
  • backgroundColor - the background color to use for thenavigationBar.
  • tintColor - the color to use for the title text and back button ordrawer button icons.
  • visible - boolean that indicates whether thenavigationBar shouldbe visible for this route.
  • translucent - iOS and Expo only, use background blur on thenavigationBar, like in the Apple Podcasts app, for example.
  • borderBottomWidth - the width of the bottom border
  • borderBottomColor - the color of the bottom border
  • renderLeft - a function that should return a React component thatwill be rendered in the left position of thenavigationBar.
  • renderTitle - a function that should return a React component thatwill be rendered in the title position of thenavigationBar.
  • renderRight - a function that should return a React component thatwill be rendered in the right position of thenavigationBar.
  • renderBackground - a function that should return a React component thatwill be rendered in the background of thenavigationBar.

TabNavigation

A minimal example using tabs:

import{StackNavigation,TabNavigation,TabNavigationItemasTabItem,}from'@expo/ex-navigation';// Treat the TabScreen route like any other route -- you may want to set// it as the initial route for a top-level StackNavigationclassTabScreenextendsReact.Component{staticroute={navigationBar:{visible:false,}}render(){return(<TabNavigationid="main"navigatorUID="main"initialTab="home"><TabItemid="home"title="Home"selectedStyle={styles.selectedTab}renderIcon={(isSelected)=><Imagesource={require('./assets/images/home.png')}/>}><StackNavigationid="home"navigatorUID="home"initialRoute={Router.getRoute('home')}/></TabItem><TabItemid="posts"title="Posts"selectedStyle={styles.selectedTab}renderIcon={(isSelected)=><Imagesource={require('./assets/images/posts.png')}/>}><StackNavigationid="posts"initialRoute={Router.getRoute('posts')}/></TabItem><TabItemid="profile"title="Profile"selectedStyle={styles.selectedTab}renderIcon={(isSelected)=><Imagesource={require('./assets/images/profile.png')}/>}><StackNavigationid="profile"initialRoute={Router.getRoute('profile')}/></TabItem></TabNavigation>);}}

See an example of TabNavigation in a real apphere.

If you'd like to switch tabs programmatically (eg: a notificationarrives and you want to jump to a notifications tab, or you tap on abutton to open your profile but within another tab) you can usejumpToTab. For the code below to work, we need thenavigatorUID propto be set on TabNavigator, as with the example above.

<TouchableOpacityonPress={()=>{this.props.navigation.performAction(({ tabs, stacks})=>{tabs('main').jumpToTab('profile');stacks('home').push(route);});}}/>

DrawerNavigation

A minimal example using the DrawerNavigation:

import{StackNavigation,DrawerNavigation,DrawerNavigationItem,}from'@expo/ex-navigation';// Treat the DrawerNavigationLayout route like any other route -- you may want to set// it as the intiial route for a top-level StackNavigationclassDrawerNavigationLayoutextendsReact.Component{staticroute={navigationBar:{visible:false,}};render(){return(<DrawerNavigationid='main'initialItem='home'drawerWidth={300}renderHeader={this._renderHeader}><DrawerNavigationItemid='home'selectedStyle={styles.selectedItemStyle}renderTitle={isSelected=>this._renderTitle('Home',isSelected)}><StackNavigationid='home'initialRoute={Router.getRoute('home')}/></DrawerNavigationItem><DrawerNavigationItemid='about'selectedStyle={styles.selectedItemStyle}renderTitle={isSelected=>this._renderTitle('About',isSelected)}><StackNavigationid='about'initialRoute={Router.getRoute('about')}/></DrawerNavigationItem></DrawerNavigation>);}_renderHeader=()=>{return(<Viewstyle={styles.header}></View>);};_renderTitle(text:string,isSelected:boolean){return(<Textstyle={[styles.titleText,isSelected ?styles.selectedTitleText :{}]}>{text}</Text>);};}conststyles=StyleSheet.create({header:{height:20},selectedItemStyle:{backgroundColor:'blue'},titleText:{fontWeight:'bold'},selectedTitleText:{color:'white'}});

Integrate with your existing Redux store

Behind the scenes ExNavigation manages your navigation state usingRedux in its own store. If you'd like to store the navigation stateon your app's store, you can use thecreateStoreWithNavigationfunction when creating the store and then manually provide theNavigationContext, initialized with your app's store.

/* Your store definition, let's say state/Store.js */import{createNavigationEnabledStore,NavigationReducer}from'@expo/ex-navigation';import{combineReducers,createStore}from'redux';constcreateStoreWithNavigation=createNavigationEnabledStore({  createStore,navigationStateKey:'navigation',});conststore=createStoreWithNavigation(/* combineReducers and your normal create store things here! */combineReducers({navigation:NavigationReducer,// other reducers}));exportdefaultstore;
/* Your routes, Router.js */import{createRouter}from'@expo/ex-navigation';importHomeScreenfrom'./HomeScreen';exportconstRouter=createRouter(()=>({home:()=>HomeScreen,}));
 /* The top level of your app, often in main.js or index.[ios/android].js */ import {   NavigationContext,   NavigationProvider,   StackNavigation, } from '@expo/ex-navigation'; import Store from './state/Store'; import Router from './Router';+const navigationContext = new NavigationContext({+  router: Router,+  store: Store,+}) return (   <Provider store={Store}>+    <NavigationProvider context={navigationContext}>       <StackNavigation yourUsualPropsHere />     </NavigationProvider>   </Provider> )

Perform navigation actions from outside of a component

You might be using some Redux middleware like saga, thunk, promise, oreffex (we recommendeffexbecause we loveasync/await). Whatever you're using, you no longerhave access tothis.props.navigator and the like. What to do?Well as long as you include your navigation state inside of your Reduxstore, you can dispatch a NavigationAction to it -- after all, this iswhatthis.props.navigator.push etc. do behind the scenes.

In the following example we callgetState anddispatch directly onyour store -- feel free to change this to whatever the equivalent isfor your context (eg: if this was effex,dispatch andgetState wouldbe passed in to thegoHome function).

import{NavigationActions}from'@expo/ex-navigation'importStorefrom'../state/Store';importRouterfrom'./Router'exportdefaultfunctiongoHome(){letnavigatorUID=Store.getState().navigation.currentNavigatorUID;Store.dispatch(NavigationActions.push(navigatorUID,Router.getRoute('home')))}

Screen Tracking / Analytics

You might want to do some screen tracking in your apps. Since the entire navigation state is in redux, screen tracking is as simple as writing a redux middleware. Below is a simple middleware that usesrouteName as the screen name for tracking screens.

importSegmentIOfrom'react-native-segment-io-analytics';constnavigationStateKey='navigation';// gets the current screen from navigation statefunctiongetCurrentScreen(getStateFn){constnavigationState=getStateFn()[navigationStateKey];// navigationState can be null when exnav is initializingif(!navigationState)returnnull;const{ currentNavigatorUID, navigators}=navigationState;if(!currentNavigatorUID)returnnull;const{ index, routes}=navigators[currentNavigatorUID];const{ routeName}=routes[index];returnrouteName;}constscreenTracking=({ getState})=>next=>action=>{if(!action.type.startsWith('EX_NAVIGATION'))returnnext(action);constcurrentScreen=getCurrentScreen(getState);constresult=next(action);constnextScreen=getCurrentScreen(getState);if(nextScreen!==currentScreen){SegmentIO.screen(nextScreen);}returnresult;}exportdefaultscreenTracking;

Android back button handling

React Native includes a globalBackHandler module. Rather than using this moduledirectly, include theAndroidBackButtonBehavior component in routes where you'dlike to control the back button.AndroidBackButtonBehavior acceptsisFocused andonBackButtonPress. IfisFocused is true, theonBackButtonPresswill fire when the user presses the back button. You need to make sure thatonBackButtonPressreturns a promise that wraps the function you want to be called. Eg.

<AndroidBackButtonBehavior isFocused={someboolean}   onBackButtonPress={()=>Promise.resolve(fireMeWhenSomeBooleanIsTrue)}>   ...</AndroidBackButtonBehavior>

About

Route-centric navigation for React Native

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors43


[8]ページ先頭

©2009-2025 Movatter.jp