Jumping back and forth

In the previous example, you told the left and right navigation buttons where they should link to by passing routes within routes. The challenge with this approach is that it takes a lot of work to keep this navigation data up-to-date, especially if all you need is simple back and forward behavior. Let's make some adjustments to the application so that the buttons automatically know which route to use.

First, let's take a look at the UI so that you can see what we're trying to achieve here:

Jumping back and forth

If you take a look at the navigation bar, you'll notice that there are a title and a forward button. But there's no back button. This is because the user is on the first screen, so there's nowhere to navigate back to. When the user moves to the second screen, they'll see a forward and a back button. Now let's take a look at the main module:

import React from 'react'; 
import { 
  AppRegistry, 
  Navigator, 
} from 'react-native'; 
 
import routes from './routes'; 
import styles from './styles'; 
 
const renderScene = (route, navigator) => ( 
  <route.Scene 
    navigator={navigator} 
    content={route.content} 
  /> 
); 
 
// The "LeftButton" and "RightButton" components 
// are passed the "routes" array as a property so 
// that they can do bounds-checking. 
const routeMapper = { 
  Title: (route, navigator) => ( 
    <route.Title 
      navigator={navigator} 
      title={route.title} 
    /> 
  ), 
  LeftButton: (route, navigator) => ( 
    <route.LeftButton 
      navigator={navigator} 
      route={route} 
      routes={routes} 
    /> 
  ), 
  RightButton: (route, navigator) => ( 
    <route.RightButton 
      navigator={navigator} 
      route={route} 
      routes={routes} 
    /> 
  ), 
}; 
 
const navigationBar = ( 
  <Navigator.NavigationBar 
    style={styles.nav} 
    routeMapper={routeMapper} 
  /> 
); 
 
// Notice how we're passing in an initial route stack 
// again? This is how we're able to use "jumpForward()" 
// and "jumpBack()". 
const JumpingBack = () => ( 
  <Navigator 
    initialRoute={routes[0]} 
    initialRouteStack={routes} 
    renderScene={renderScene} 
    navigationBar={navigationBar} 
  /> 
); 
 
AppRegistry.registerComponent( 
  'JumpingBack', 
  () => JumpingBack 
); 

There are two things that we've changed from the previous example. First, you can see that we're passing the initialRouteStack property again. This means that all the routes in this array are rendered, but only initialRoute is displayed. We're doing this because in order to jump back and forth without prior knowledge of the next route, we need a route stack.

Another way to think about this navigation model is in terms of an array index. We're starting at 0, the first route in the stack. When the user presses forward, the index is incremented. When the user presses back, the index is decremented. Let's take a look at the simplified routes module now:

import mainRoute from './scene'; 
 
const firstRoute = { 
  title: 'First', 
  content: 'First Content', 
}; 
 
const secondRoute = { 
  title: 'Second', 
  content: 'Second Content', 
}; 
 
const thirdRoute = { 
  title: 'Third', 
  content: 'Third Content', 
}; 
 
// The exported routes no longer contain properties 
// that point to other routes. 
export default [ 
  Object.assign(firstRoute, mainRoute), 
  Object.assign(secondRoute, mainRoute), 
  Object.assign(thirdRoute, mainRoute), 
]; 

This is much easier to digest. There are no more left and right button components. Finally, let's take a look at the Scene component that renders the screen:

import React, { PropTypes } from 'react'; 
import { View, Text } from 'react-native'; 
 
import styles from './styles'; 
 
const Scene = ({ content }) => ( 
  <View style={styles.container}> 
    <Text style={styles.content}> 
      {content} 
    </Text> 
  </View> 
); 
 
Scene.propTypes = { 
  content: PropTypes.node.isRequired, 
}; 
 
const Title = ({ title }) => ( 
  <Text style={styles.title}>{title}</Text> 
); 
 
Title.propTypes = { 
  title: PropTypes.node.isRequired, 
}; 
 
// The left button is the "back" button. Notice that we 
// don't require a specific route here - we just use 
// the "jumpBack()" method. 
const LeftButton = ({ navigator, route, routes }) => 
  routes.indexOf(route) === 0 ? null : ( 
    <Text onPress={() =>navigator.jumpBack()}> 
      
      &#9654:
    </Text> 
  ); 
 
LeftButton.propTypes = { 
  navigator: PropTypes.object.isRequired, 
  route: PropTypes.object.isRequired, 
  routes: PropTypes.array.isRequired, 
}; 
 
// The right button is the "forward" button. Notice that 
// we don't require a specific route here - we just use 
// the "jumpForward()" method. 
const RightButton = ({ navigator, route, routes }) => 
  routes.indexOf(route) === (routes.length - 1) ? null : ( 
    <Text onPress={() => navigator.jumpForward()}> 
    
      &#9664:
    </Text> 
  ); 
 
RightButton.propTypes = { 
  navigator: PropTypes.object.isRequired, 
  route: PropTypes.object.isRequired, 
  routes: PropTypes.array.isRequired, 
}; 
 
export const route = { 
  Scene, 
  Title, 
  LeftButton, 
  RightButton, 
}; 
 
export default route; 

As you can see, the left and right buttons each render an arrow that uses the jumpBack() and jumpForward() methods, respectively. There's a simple bounds checking mechanism in place for each Press event that makes sure the button should actually render. For example, if the user is at the beginning of the route stack, then there's no need to render a back button. This little piece of additional logic is powerful, because this component doesn't need to rely on any routes being passed to it, only Navigator methods.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset