Dynamic scenes

Some apps, like the one we've been working on in this chapter, have very similar scenes. In fact, they're so similar that having three unique components for this purpose feels awkward and repetitive. It would make more sense to have a single scene and navigation bar and pass them the dynamic pieces of information through the route objects.

Let's make some changes to the application, starting with the main module so that we don't need duplicate components anymore:

import React from 'react'; 
import { 
  AppRegistry, 
  Navigator, 
} from 'react-native'; 
 
import routes from './routes'; 
import styles from './styles'; 
 
// The scene content now comes from the "route". 
const renderScene = route => ( 
  <route.Scene 
    content={route.content} 
  /> 
); 
 
// The "routeMapper" object now has to pass each navbar item 
// more properties since the same component is used now. For 
// example, the "LeftButton" component passes in "content" 
// and the "route" that's to be activated if the user presses 
// the button. 
const routeMapper = { 
  Title: (route, navigator) => ( 
    <route.Title 
      navigator={navigator} 
      title={route.title} 
    /> 
  ), 
  LeftButton: (route, navigator) => ( 
    <route.LeftButton 
      navigator={navigator} 
      content={route.leftTitle} 
      route={route.leftRoute} 
    /> 
  ), 
  RightButton: (route, navigator) => ( 
    <route.RightButton 
      navigator={navigator} 
      content={route.rightTitle} 
      route={route.rightRoute} 
    /> 
  ), 
}; 
 
const navigationBar = ( 
  <Navigator.NavigationBar 
    style={styles.nav} 
    routeMapper={routeMapper} 
  /> 
); 
 
// The "Navigator" component no longer has an initial 
// route stack passed to it. Instead, current routes 
// are "replaced" by new routes. 
const DynamicRouteData = () => ( 
  <Navigator 
    initialRoute={routes[0]} 
    renderScene={renderScene} 
    navigationBar={navigationBar} 
  /> 
); 
 
AppRegistry.registerComponent( 
  'DynamicRouteData', 
  () => DynamicRouteData 
); 

You can see here that the code looks more or less as it did in the previous section, only now we're passing more properties to the components as they're rendered. For example, the main Scene component gets its content passed to it from a property. The left button gets its content and the route to follow passed in as property values.

Now, let's take a look at the scene module that's used for every screen in the application:

import React, { PropTypes } from 'react'; 
import { View, Text } from 'react-native'; 
 
import styles from './styles'; 
 
// The content rendered by the scene now comes from 
// a property, since this is the only scene component 
// in the whole app. 
const Scene = ({ content }) => ( 
  <View style={styles.container}> 
    <Text style={styles.content}> 
      {content} 
    </Text> 
  </View> 
); 
 
Scene.propTypes = { 
  content: PropTypes.node.isRequired, 
}; 
 
// The "title" value also comes from a prop. 
const Title = ({ title }) => ( 
  <Text style={styles.title}>{title}</Text> 
); 
 
Title.propTypes = { 
  title: PropTypes.node.isRequired, 
}; 
 
// The left button label and the route that's activated 
// on press are passed in as properties. 
const LeftButton = ({ navigator, route, content }) => ( 
  <Text onPress={() => navigator.replace(route)}> 
    {content} 
  </Text> 
); 
 
LeftButton.propTypes = { 
  navigator: PropTypes.object.isRequired, 
  route: PropTypes.object.isRequired, 
  content: PropTypes.node.isRequired, 
}; 
 
// The right button label and the route that's activated 
// on press are passed in as properties. 
const RightButton = ({ navigator, route, content }) => ( 
  <Text onPress={() => navigator.replace(route)}> 
    {content} 
  </Text> 
); 
 
RightButton.propTypes = { 
  navigator: PropTypes.object.isRequired, 
  route: PropTypes.object.isRequired, 
  content: PropTypes.node.isRequired, 
}; 
 
export default { 
  Scene, 
  Title, 
  LeftButton, 
  RightButton, 
}; 

The key change between this module and the other scene modules in the preceding sections is that nothing is hardcoded here. The labels, and even the routes themselves, are passed in as component properties. Another change I've introduced here is the use of the replace() method to change the current route, instead of the jumpTo() method. The difference is that, since we don't have an active route stack, we can just unmount what's already rendered and re-render the new component. This should be really efficient because the component type is the same; it's just the property values that have changed.

Lastly, let's take a look at the routes module:

import mainRoute from './scene'; 
 
// Each route object has enough data to render 
// the dynamic parts of the scene and the navbar. 
const firstRoute = { 
  index: 0, 
  title: 'First', 
  leftTitle: 'Third', 
  rightTitle: 'Second', 
  content: 'First Content', 
}; 
 
const secondRoute = { 
  index: 1, 
  title: 'Second', 
  leftTitle: 'First', 
  rightTitle: 'Third', 
  content: 'Second Content', 
}; 
 
const thirdRoute = { 
  index: 2, 
  title: 'Third', 
  leftTitle: 'Second', 
  rightTitle: 'First', 
  content: 'Third Content', 
}; 
 
// Each route is extended with the components from the 
// scene. This means that the same component is reused, 
// and new property values change the data as the 
// user navigates the application. 
export default [ 
  Object.assign(firstRoute, mainRoute, { 
    leftRoute: thirdRoute, 
    rightRoute: secondRoute, 
  }), 
  Object.assign(secondRoute, mainRoute, { 
    leftRoute: firstRoute, 
    rightRoute: thirdRoute, 
  }), 
  Object.assign(thirdRoute, mainRoute, { 
    leftRoute: secondRoute, 
    rightRoute: firstRoute, 
  }), 
]; 

The components that get rendered come from mainRoute. All we have to do is use Object.assign() to share the references to these components with each route.

Note

Technically, we don't have to export any array from this module because we're only passing the first route to the navigator. However, I'm not sure I like the assumption that you'll never use these routes as the initial route stack. When in doubt, export all your routes as an array.

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

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