Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds
Arrow up icon
GO TO TOP
Mastering React Native

You're reading from   Mastering React Native Learn Once, Write Anywhere

Arrow left icon
Product type Paperback
Published in Jan 2017
Publisher Packt
ISBN-13 9781785885785
Length 496 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Authors (2):
Arrow left icon
Eric Masiello Eric Masiello
Author Profile Icon Eric Masiello
Eric Masiello
Jacob Friedmann Jacob Friedmann
Author Profile Icon Jacob Friedmann
Jacob Friedmann
Arrow right icon
View More author details
Toc

Table of Contents (13) Chapters Close

Preface 1. Building a Foundation in React FREE CHAPTER 2. Saying HelloWorld in React Native 3. Styling and Layout in React Native 4. Starting our Project with React Native Components 5. Flux and Redux 6. Integrating with the NYT API and Redux 7. Navigation and Advanced APIs 8. Animation and Gestures in React Native 9. Refactoring for Android 10. Using and Writing Native Modules 11. Preparing for Production 12. React Native Tools and Resources

Using native modules

In React Native, we manage dependencies to our project in much the same way as other web or Node applications, that is, using npm, the Node Package Manager. Many of the dependencies we use will contain only React Native JavaScript code, but some will have native code as well. The installation process for dependencies containing native code differs slightly from that of pure JS dependencies.

Installing native modules

In order to build out our new profile page and to make our application a bit more aesthetically pleasing, we'll use an icon library called react-native-vector-icons. The first thing we will need to do is simply install the library with npm like we would any other dependency:

npm install --save react-native-vector-icons

This library contains native modules, so we are not done yet. Most libraries that contain native modules will provide one or more additional install steps. The end goal of the installation is to link the native code from the dependency to the platform-specific code of the main project. This can be done in one of a few ways.

The first installation option that most native module libraries will provide is a manual installation. This method is cumbersome and involves updating several project configuration files as well as native code files.

The second option that may be offered is to use a platform-specific package manager in addition to npm. On iOS, this probably means CocoaPods, and on Android, Gradle. These tools work well for the job and, compared to the manual option, is much less painful. However, it also adds two additional package managers and configurations to the project.

If these two options don't sound exactly ideal, you're in luck. A tool was developed to reduce some of the friction involved in using native dependencies called rnmp (react native package manager). Because it is much easier, most libraries are moving toward this option. In fact, it is so common and useful that rnpm was eventually merged into the React Native command line client library, which means it should already be installed.

Now we can use the React Native command line client to link the native files from the react-native-vector-icons library to our project:

react-native link react-native-vector-icons

We've now downloaded the dependency using npm and then linked the native code files, so we are all set to begin using icons in our project. We could also combine those two steps into a single command:

react-native install react-native-vector-icons

Using the library

The react-native-vector-icons library gives us a few components that we can use within our project. The Icon component can be used to simply display icons anywhere in our project. We will also use the Icon.TabBarItemIOS component that comes with the library that can be used in place of the React Native component TabBarIOS.Item and gives us access to a more robust collection of icons.

Profile page

The first thing we need to do is make a Profile component that can be used to display the profile page. We'll put this new component in a file called src/components/Profile.js:

import React, { Component } from 'react'; 
import { 
  View, 
  StyleSheet 
} from 'react-native'; 
import Title from './Title'; 
import AppText from './AppText'; 
import * as globalStyles from '../styles/global'; 
 
export default class Profile extends Component { 
 
  render() { 
    return ( 
      <View style={[globalStyles.COMMON_STYLES.pageContainer, styles.container]}> 
        <Title>Username</Title> 
        <AppText>Your Name</AppText> 
      </View> 
    ); 
  } 
 
} 
 
const styles = StyleSheet.create({ 
  container: { 
    justifyContent: 'center', 
    alignItems: 'center' 
  } 
}); 

So far, this looks very similar to other components we've made. First import React, react-native and other application modules we need:

import React, { Component } from 'react'; 
import { 
  View, 
  StyleSheet 
} from 'react-native'; 
import Title from './Title'; 
import AppText from './AppText'; 
import * as globalStyles from '../styles/global'; 

We then create a class for the Profile component and define its render() method. Note that this component in its current state could easily be a functional component, but we're making it a class so that we can add more sophisticated behavior later on:

export default class Profile extends Component { 
 
  render() { 
    return ( 
      <View style={[globalStyles.COMMON_STYLES.pageContainer, styles.container]}> 
        <Title>Username</Title> 
        <AppText>Your Name</AppText> 
      </View> 
    ); 
  } 
 
} 

Finally, we add some styles in a StyleSheet to make the page look better:

const styles = StyleSheet.create({ 
  container: { 
    justifyContent: 'center', 
    alignItems: 'center' 
  } 
}); 

Now, we're going to use the react-native-vector-icons library to add an avatar image as a placeholder for the user's profile picture. The first step here is to import the Icon component. When we import this component, we have to specify which icon font library we want to use. For our project, we'll use the EvilIcons icon font library:

import React, { Component } from 'react'; 
import { 
  View, 
  StyleSheet 
} from 'react-native'; 
import Icon from 'react-native-vector-icons/EvilIcons'; 
import Title from './Title'; 
import AppText from './AppText'; 
import * as globalStyles from '../styles/global'; 

Next, we'll add some additional styles to the components StyleSheet for the avatar icon:

const styles = StyleSheet.create({ 
  container: { 
    justifyContent: 'center', 
    alignItems: 'center' 
  }, 
  avatarIcon: { 
    color: globalStyles.HEADER_TEXT_COLOR, 
    fontSize: 200 
  } 
}); 

Finally, we'll add an Icon in the Profile component's render() method. We'll use the new styles and choose the icon named user:

render() { 
  return ( 
    <View style={[globalStyles.COMMON_STYLES.pageContainer, styles.container]}> 
      <Icon 
        name="user" 
        style={styles.avatarIcon} 
      /> 
      <Title>Username</Title> 
      <AppText>Your Name</AppText> 
    </View> 
  ); 
} 

Now that we have a working profile page, we need to make it accessible from within the application. We'll do this by adding it in the HomeScreen.ios.js and HomeScreen.android.js files.

Adding the profile to the iOS home screen

On our iOS home screen, we'll need to add an additional tab for the profile page. We'll also swap out the React Native TabBarIOS.Item components with the Icon.TabBarItemIOS component from the icon library:

import React, { PropTypes } from 'react'; 
import { 
  TabBarIOS, 
  StatusBar 
} from 'react-native'; 
import Icon from 'react-native-vector-icons/EvilIcons'; 
import NewsFeedContainer from '../containers/NewsFeedContainer'; 
import SearchContainer from '../containers/SearchContainer'; 
import BookmarksContainer from '../containers/BookmarksContainer'; 
import Profile from './Profile'; 
import * as globalStyles from '../styles/global'; 
 
//Set the status bar for iOS to light 
StatusBar.setBarStyle('light-content'); 
 
const HomeScreen = ({ selectedTab, tab }) => ( 
  <TabBarIOS 
    barTintColor={globalStyles.BAR_COLOR} 
    tintColor={globalStyles.LINK_COLOR} 
    translucent={false} 
  > 
    <Icon.TabBarItemIOS 
      iconName={'star'} 
      title={'News'} 
      selected={selectedTab === 'newsFeed'} 
      onPress={() => tab('newsFeed')} 
    > 
      <NewsFeedContainer/> 
    </Icon.TabBarItemIOS> 
    <Icon.TabBarItemIOS 
      iconName={'search'} 
      title={'Search'} 
      selected={selectedTab === 'search'} 
      onPress={() => tab('search')} 
    > 
      <SearchContainer/> 
    </Icon.TabBarItemIOS> 
    <Icon.TabBarItemIOS 
      iconName={'paperclip'} 
      title={'Bookmarks'} 
      selected={selectedTab === 'bookmarks'} 
      onPress={() => tab('bookmarks')} 
    > 
      <BookmarksContainer /> 
    </Icon.TabBarItemIOS> 
    <Icon.TabBarItemIOS 
      iconName={'user'} 
      title={'Profile'} 
      selected={selectedTab === 'profile'} 
      onPress={() => tab('profile')} 
    > 
      <Profile /> 
    </Icon.TabBarItemIOS> 
  </TabBarIOS> 
); 
 
HomeScreen.propTypes = { 
  selectedTab: PropTypes.string, 
  tab: PropTypes.func.isRequired 
}; 
 
export default HomeScreen; 

First, we add an import statement for our new Profile component as well as one for the Icon component:

import React, { PropTypes } from 'react'; 
import { 
  TabBarIOS, 
  StatusBar 
} from 'react-native'; 
import Icon from 'react-native-vector-icons/EvilIcons'; 
import NewsFeedContainer from '../containers/NewsFeedContainer'; 
import SearchContainer from '../containers/SearchContainer'; 
import BookmarksContainer from '../containers/BookmarksContainer'; 
import Profile from './Profile'; 
import * as globalStyles from '../styles/global'; 

Next, we'll change each of the tab bar items to use Icon.TabBarItemIOS. This component needs two new props, one called iconName, which tells the component which icon to render, and one called title, which specifies the text that should be shown below the tab:

<Icon.TabBarItemIOS 
  iconName={'star'} 
  title={'News'} 
  selected={selectedTab === 'newsFeed'} 
  onPress={() => tab('newsFeed')} 
> 
  <NewsFeedContainer /> 
</Icon.TabBarItemIOS>

Notice that we've changed the name of the first tab to use the more appropriate News title. We can do this because now that we aren't using system icons, we have complete control over the text displayed.

Finally, we need to add a new tab for the profile page that follows the same pattern as our other tabs. For this tab, we'll use the same user icon that we used for the avatar:

<Icon.TabBarItemIOS 
  iconName={'user'} 
  title={'Profile'} 
  selected={selectedTab === 'profile'} 
  onPress={() => tab('profile')} 
> 
  <Profile /> 
</Icon.TabBarItemIOS> 

In order to make it selectable, we'll also need to add a new profile tab to the available routes in the navigationReducer.js file:

const routes = { 
  home: { 
    key: 'home', 
    component: HomeScreenContainer, 
    index: 0, 
    routes: [ 
      { key: 'newsFeed', modal: undefined }, 
      { key: 'search' }, 
      { key: 'bookmarks' }, 
      { key: 'profile' } 
    ] 
  }, 
  intro: { 
    key: 'intro', 
    component: IntroScreen 
  }, 
  onboarding: { 
    key: 'onboarding', 
    component: Onboarding 
  } 
}; 

We should now be able to open the application in iOS and see our new, much more attractive, tab bar icons as well as the profile page as shown in the following screenshot:

Adding the profile to the iOS home screen

Adding the profile to the Android home screen

We will also need to update our Android home screen, which uses a drawer layout instead of a tab bar to account for the new profile page:

import React, { Component, PropTypes } from 'react'; 
import { 
  DrawerLayoutAndroid, 
  View, 
  StyleSheet 
} from 'react-native'; 
import NewsFeedContainer from '../containers/NewsFeedContainer'; 
import SearchContainer from '../containers/SearchContainer'; 
import BookmarksContainer from '../containers/BookmarksContainer'; 
import Profile from './Profile'; 
import AppText from './AppText'; 
import * as globalStyles from '../styles/global'; 
 
const navConfig = { 
  order: ['newsFeed', 'search', 'bookmarks', 'profile'], 
  newsFeed: { 
    title: 'News', 
    view: <NewsFeedContainer />, 
    tab: 'newsFeed' 
  }, 
  search: { 
    title: 'Search', 
    view: <SearchContainer />, 
    tab: 'search' 
  }, 
  bookmarks: { 
    title: 'Bookmarks', 
    view: <BookmarksContainer />, 
    tab: 'bookmarks' 
  }, 
  profile: { 
    title: 'Profile', 
    view: <Profile />, 
    tab: 'profile' 
  } 
}; 
 
export default class HomeScreen extends Component { 
  constructor(props) { 
    super(props); 
    this.renderDrawer = this.renderDrawer.bind(this); 
    this.showNav = this.showNav.bind(this); 
  } 
 
  showNav() { 
    this.drawer.openDrawer(); 
  } 
 
  renderDrawer() { 
    return ( 
      <View style={styles.drawer}> 
        {navConfig.order.map(key => ( 
          <AppText 
            key={key} 
            style={styles.drawerItem} 
            onPress={() => { 
              this.props.tab(navConfig[key].tab); 
              this.drawer.closeDrawer(); 
            }} 
          > 
            {navConfig[key].title} 
          </AppText> 
        ))} 
      </View> 
    ); 
  } 
 
  render() { 
    return ( 
      <DrawerLayoutAndroid 
        ref={(c) => { this.drawer = c; }} 
        drawerWidth={310} 
        drawerPosition={DrawerLayoutAndroid.positions.Left} 
        drawerBackgroundColor="rgba(0,0,0,0.5)" 
        renderNavigationView={this.renderDrawer} 
      > 
        <View style={styles.container}> 
          <AppText 
            style={styles.menuButton} 
            onPress={this.showNav} 
          >Menu</AppText> 
          {navConfig[this.props.selectedTab].view} 
        </View> 
      </DrawerLayoutAndroid> 
    ); 
  } 
} 
 
HomeScreen.propTypes = { 
  selectedTab: PropTypes.string, 
  tab: PropTypes.func.isRequired 
}; 
 
const styles = StyleSheet.create({ 
  container: { 
    backgroundColor: globalStyles.BG_COLOR, 
    flex: 1 
  }, 
  drawer: { 
    backgroundColor: globalStyles.BG_COLOR, 
    flex: 1, 
    padding: 10 
  }, 
  drawerItem: { 
    fontSize: 20, 
    marginBottom: 5 
  }, 
  menuButton: { 
    marginHorizontal: 10, 
    marginTop: 10, 
    color: globalStyles.LINK_COLOR 
  } 
}); 

We first import the Profile component:

import React, { Component, PropTypes } from 'react'; 
import { 
  DrawerLayoutAndroid, 
  View, 
  StyleSheet 
} from 'react-native'; 
import NewsFeedContainer from '../containers/NewsFeedContainer'; 
import SearchContainer from '../containers/SearchContainer'; 
import BookmarksContainer from '../containers/BookmarksContainer'; 
import Profile from './Profile'; 
import AppText from './AppText'; 
import * as globalStyles from '../styles/global'; 

We then need to add the profile to the navConfig object in order to add it to the drawer's menu:

const navConfig = { 
  order: ['newsFeed', 'search', 'bookmarks', 'profile'], 
  newsFeed: { 
    title: 'News', 
    view: <NewsFeedContainer />, 
    tab: 'newsFeed' 
  }, 
  search: { 
    title: 'Search', 
    view: <SearchContainer />, 
    tab: 'search' 
  }, 
  bookmarks: { 
    title: 'Bookmarks', 
    view: <BookmarksContainer />, 
    tab: 'bookmarks' 
  }, 
  profile: { 
    title: 'Profile', 
    view: <Profile />, 
    tab: 'profile' 
  } 
}; 

Note that we have to add a new profile key to this object in addition to the string 'profile' to the array describing the order of the menu options. Once we've added these things, our Android application should have the new profile page in its drawer menu:

Adding the profile to the Android home screen

We've now successfully incorporated an open source native module into both the iOS and Android versions of our application. Next, we'll develop our profile page further and write our own native modules.

lock icon The rest of the chapter is locked
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image