Connect with us

Technology

Getting Began with the React Native Navigation Library – SitePoint


Some of the essential elements of React Native app improvement is the navigation. It’s what permits customers to get to the pages they’re in search of. That’s why it’s essential to decide on the perfect navigation library to fit your wants.

In case your app has loads of screens with comparatively advanced UI, it could be value exploring React Native Navigation as a substitute of React Navigation. It’s because there’ll at all times be efficiency bottlenecks with React Navigation, since it really works off the identical JavaScript thread as the remainder of the app. The extra advanced your UI, the extra information needs to be handed to that bridge, which might doubtlessly sluggish it down.

On this tutorial, we’ll be wanting on the React Native Navigation library by Wix, an alternate navigation library for many who are in search of a smoother navigation efficiency for his or her React Native apps.

Stipulations

Information of React and React Native is required to observe this tutorial. Prior expertise with a navigation library reminiscent of React Navigation is non-obligatory.

Readers are additionally anticipated to have Node and Yarn put in regionally, in addition to a React Native improvement atmosphere. Yow will discover assist getting arrange right here. Remember to select React Native CLI Quickstart.

App Overview

As a way to reveal the way to use the library, we’ll be making a easy app that makes use of it. The app could have 5 screens in whole:

  • Initialization: this serves because the preliminary display for the app. If the consumer is logged in, it is going to routinely navigate to the house display. If not, the consumer is navigated to the login display.
  • Login: this permits the consumer to log in to allow them to view the house, gallery, and feed. To simplify issues, the login will simply be mocked; no precise authentication code will probably be concerned. From this display, the consumer also can go to the forgot-password display.
  • ForgotPassword: a filler display, which asks for the consumer’s e mail tackle. This may merely be used to reveal stack navigation.
  • Residence: the preliminary display that the consumer will see once they log in. From right here, they’ll additionally navigate to both the gallery or feed screens by way of a backside tab navigation.
  • Gallery: a filler display which exhibits a photograph gallery UI.
  • Feed: a filler display which exhibits a information feed UI.

Right here’s what the app will seem like:

Yow will discover the supply code of the pattern app on this GitHub repo.

Bootstrapping the App

Let’s begin by producing a brand new React Native mission:

npx react-native init RNNavigation

Subsequent, set up the dependencies of the app:

  • react-native-navigation: the navigation library that we’re going to make use of. Since its title may be very lengthy, I’ll be referring to it as RNN any longer.
  • @react-native-async-storage/async-storage: for saving information to the app’s native storage.
  • react-native-vector-icons: for displaying icons for the underside tab navigation.
yarn add react-native-navigation @react-native-async-storage/async-storage react-native-vector-icons

As soon as these are put in, we have to hyperlink the corresponding native module to the app. Be aware that I’m solely going to cowl module linking for React Native 0.60 and above. Should you’re utilizing an older model of React Native, you’ll have to do this by way of the previous approach which is to make use of the react-native hyperlink command. This could hyperlink the native modules for all of the packages we’ve simply put in. However typically errors can happen, so that you’ll should examine the documentation for the package deal and examine their guide set up directions.

Should you’re utilizing React Native 0.60 and above, we’ll should hyperlink RNN, AsyncStorage, and Vector Icons in numerous methods.

For RNN, you are able to do that by executing the next command on the root of the mission listing:

npx rnn-link

For AsyncStorage, you are able to do that by executing the next command (nonetheless on the root listing of the mission):

npx pod-install

Lastly, for Vector Icons you’ll should navigate to the android listing for Android apps and ios listing for iOS apps. For Android, edit the android/app/construct.gradle file and add the next after the final apply from name:

apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"

For iOS, execute the next command whereas contained in the ios listing:

pod set up

Lastly, replace index.js like so:

import { Navigation } from "react-native-navigation";
import App from "./App";

Navigation.registerComponent('com.myApp.WelcomeScreen', () => App);
Navigation.occasions().registerAppLaunchedListener(() => {
   Navigation.setRoot({
     root: {
       stack: {
         youngsters: [
           {
             component: {
               name: 'com.myApp.WelcomeScreen'
             }
           }
         ]
       }
     }
  });
});

Attempting Out the Undertaking

Earlier than we proceed to truly constructing the app, let’s first check out the mission to see if the modules have been efficiently put in. First, run Metro Bundler:

npx react-native begin

Then run the app on both platforms:

npx react-native run-android
npx react-native run-ios

If there have been no points with the packages, it is best to be capable to see the default React Native mission welcome display. Should you see this display, now you can proceed with constructing the app. In any other case, take a look at the Frequent Points part beneath to troubleshoot the issue.

Frequent Points

  1. The primary difficulty that generally happens is when the linking of the native modules fails. This normally happens with RNN as they’ve a customized script for linking the native modules. That may fail primarily based on the React Native model you’re utilizing. If that’s the case, then observe the guide set up directions within the documentation:
  1. The second frequent difficulty is that this: “React Native multidex error: The variety of methodology references in a .dex file can not exceed 64K”. This happens when the app (and the libraries you’re utilizing) exceeds a sure variety of strategies. On this case, it’s round 64,000 (it’s 65,536 to be precise). That is the restrict of the Android construct structure. To resolve this difficulty, you possibly can allow multidex help. To try this, open your android/app/construct.gradle file and add the next below defaultConfig and dependencies:
defaultConfig {
  // ...
  multiDexEnabled true
}
// ...
dependencies {
  // ...
  implementation 'com.android.help:multidex:1.0.3'
}

These are the 2 most typical points you might encounter whereas attempting to observe this tutorial. Should you encounter every other points, let me know or seek for the difficulty. Normally, somebody has already encountered it earlier than and also you’ll discover the difficulty on the mission’s points on GitHub.

Constructing the App

Now we’re able to lastly begin constructing the app.

index.js

First, open the prevailing index.js on the basis of the mission listing and change its contents with the code beneath. This serves because the entry level of the app. Should you seen, we now not should register the principle app part utilizing React Native’s AppRegistry. As a substitute, we’re now utilizing RNN’s registerComponent() methodology. This has to do with the updates we did earlier to the MainActivity.java and AppDelegate.m file.

The registerComponent() methodology accepts the display’s distinctive title and the part to make use of to render the display. As soon as it’s registered, we name the registerAppLaunchedListener() methodology to set the basis display for the app to LoadingScreen. That is just like what the AppRegistry.registerComponent() does:


import { Navigation } from "react-native-navigation";
import Icon from "react-native-vector-icons/FontAwesome";
Icon.loadFont();

import Loading from "./src/screens/Loading"; 

import "./loadIcons"; 

Navigation.registerComponent("LoadingScreen", () => Loading);

Navigation.occasions().registerAppLaunchedListener(() => {
  
  Navigation.setRoot({
    root: {
      part: {
        title: "LoadingScreen",
      },
    },
  });
});

Loading Display

The loading display serves because the entry level of the app. However you might be asking why a loading display? Why not a login display as a substitute? It’s because our pattern app has a mock login system, which means that we first have to find out if a consumer is already logged in or not. Utilizing a loading display works higher than having to initially load a login display solely to seek out out {that a} consumer is already logged in, so we then should navigate them to the house display.

Begin by making a src/screens/Loading.js file and add the next:


import React, { Part } from "react";
import { View, Textual content, ActivityIndicator, StyleSheet } from "react-native";

import { goToLogin, goToTabs } from "../../navigation"; 

import AsyncStorage from "@react-native-async-storage/async-storage";

Subsequent, create the part itself. When the part is mounted, we attempt to get the username of the logged-in consumer from native storage. If it exists, we navigate the consumer to the tabs, in any other case to the login display:

export default class Loading extends Part {
  async componentDidMount() {
    const username = await AsyncStorage.getItem("username");
    if (username) {
      goToTabs(world.icons, username);
    } else {
      goToLogin();
    }
  }

  render() {
    
    return (
      <View model={kinds.container}>
        <ActivityIndicator measurement="massive" shade="#0000ff" />
      </View>
    );
  }
}

const kinds = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "heart",
    alignItems: "heart",
  },
});

Within the above code, discover we’re passing world.icons as an argument to the goToTabs() operate. That worth is being set within the loadIcons.js that we imported from the index.js file earlier. Its job is to load the icons for use for the underside tabs, as you’ll see later.

That is the place we register all of the screens of the app and declare our navigation features for navigating between the login display and the tabbed screens:


import { Navigation } from "react-native-navigation";

import Login from "./src/screens/Login";
import ForgotPassword from "./src/screens/ForgotPassword";
import Residence from "./src/screens/Residence";
import Feed from "./src/screens/Feed";
import Gallery from "./src/screens/Gallery";

Navigation.registerComponent("LoginScreen", () => Login);
Navigation.registerComponent("ForgotPasswordScreen", () => ForgotPassword);
Navigation.registerComponent("HomeScreen", () => Residence);
Navigation.registerComponent("FeedScreen", () => Feed);
Navigation.registerComponent("GalleryScreen", () => Gallery);

The goToLogin() operate creates a stack navigation. In RNN, these navigation sorts are referred to as “Layouts”. Presently, there are solely three: stacks, tabs, and drawers. We’ll solely use stack and tabs on this tutorial, however right here’s a quick overview of every one:

  • Stack: every new display you navigate to is laid out on high of the present one. So once you return to the earlier display, the thought is to easily “pop” the present display out of the stack. We’ll be utilizing the stack navigation to navigate between the Login display and ForgotPassword display.
  • Tab: every display may be accessed by way of a backside tab navigation. Every tab has each icon and textual content on it to explain the display it navigates the consumer to. This kind of navigation is often used if there are two or extra important screens inside the app. Having a backside tab navigation permits for straightforward entry between these screens. We’ll be utilizing the tab navigation to navigate between the Residence, Gallery, and Feed screens.
  • Drawer: additionally referred to as the facet menu. That is referred to as drawer as a result of it’s generally hidden inside a hamburger icon and it solely exhibits the menu below it when clicked on.

Going again to the code, we’ve solely added the Login display as a toddler of stack navigation, although the ForgotPassword display is a part of it as properly. As talked about earlier, we’ll be utilizing stack navigation to navigate between the Login display and the ForgotPassword display. But we’ve solely added the Login display right here as a toddler. Including it is going to merely make it because the default display for the stack. In a stack navigation, it is best to solely add the preliminary display for that particular stack because the baby, as you’ll see later.

The minimal requirement for a kid is so as to add the title property for every display. That is the title of the display for use for rendering. This ought to be the identical title you used once you registered the part:

export const goToLogin = () =>
  Navigation.setRoot({
    root: {
      stack: {
        
        id: "stackMain",
        youngsters: [
          {
            component: {
              name: "LoginScreen",
            },
          },
        ],
      },
    },
  });

Be aware: supplying an ID for the navigation isn’t required, but it surely’s good observe — particularly if you recognize that you simply’ll begin utilizing the identical structure kind a number of instances in your app.

Subsequent, add the goToTabs() operate. In contrast to the earlier operate, this accepts two arguments: icons and username. icons is the array of icons for use for the person tabs, whereas username is the username of the consumer who logged in. This time, we’re utilizing the bottomTabs navigation. Because the title suggests, this permits the consumer to navigate between screens utilizing backside tabs. You may create backside tabs utilizing the following format:

const iconColor = "#444";
const selectedIconColor = "#0089da";

export const goToTabs = (icons, username) => {
  Navigation.setRoot({
    root: {
      bottomTabs: {
        

        id: "bottomTabsMain",
        youngsters: [
          {
            component: {
              name: "HomeScreen",
              options: {
                bottomTab: {
                  fontSize: 11,
                  text: "Home",
                  icon: icons[0],
                  iconColor,
                  selectedIconColor,
                },
              },

              
              passProps: {
                username,
              },
            },
          },

          {
            part: {
              title: "GalleryScreen",
              choices: {
                bottomTab: {
                  fontSize: 11,
                  textual content: "Gallery",
                  icon: icons[1],
                  iconColor,
                  selectedIconColor,
                },
              },
            },
          },

          {
            part: {
              title: "FeedScreen",
              choices: {
                bottomTab: {
                  fontSize: 11,
                  textual content: "Feed",
                  icon: icons[2],
                  iconColor,
                  selectedIconColor,
                },
              },
            },
          },
        ],
      },
    },
  });
};

As you’ve seen from the code above, this gorgeous a lot makes use of the identical format because the stack navigation. The one distinction is that, this time, we’re additionally specifying an choices property for the person bottomTab. These choices are largely used for configuring the kinds of the person tab. They’re self-explanatory, so I gained’t go into element, however I simply wish to clarify the icon property. By default, this accepts a neighborhood picture that’s required by a require('./path/to/picture.png') name. However since we’ve already put in Vector Icons, we’d as properly use it because the icon supply as a substitute. The one downside is that we will’t actually provide a React part as the worth for the icon as a result of it expects a useful resource. The icons parameter accepts an array of icon useful resource and that’s what we’re utilizing as a substitute. You’ll learn the way we’re loading these within the subsequent part.

Be aware: you will discover extra styling choices for backside tabs within the official documentation for Styling. Simply search for bottomTabs or bottomTab.

loadIcons.js

Right here’s the code for the loadIcons file that we imported within the index.js file earlier. This makes use of icons from FontAwesome. Right here, we’re utilizing the getImageSource() methodology from Vector Icons to get the precise picture useful resource. This enables us to make use of it as an icon for the underside tabs:


import Icon from "react-native-vector-icons/FontAwesome";
Icon.loadFont();

(operate() {
  Promise.all([
    Icon.getImageSource("home", 11), 
    Icon.getImageSource("image", 11),
    Icon.getImageSource("rss-square", 11),
  ]).then(async (values) => {
    world.icons = values; 
  });
})();

Login Display

login screen

The Login display is the default display that the consumer will see in the event that they aren’t logged in. From right here, they’ll log in by getting into their username or they’ll click on on forgot password to view the display for resetting their password. As talked about earlier, all of that is simply mocked and no precise authentication code is used:


import React, { Part } from "react";
import { Navigation } from "react-native-navigation";
import {
  View,
  Textual content,
  TextInput,
  Button,
  TouchableOpacity,
  StyleSheet,
} from "react-native";
import AsyncStorage from "@react-native-async-storage/async-storage";

import { goToTabs } from "../../navigation";

export default class Login extends Part {
  static get choices() {
    return {
      topBar: {
        seen: false, 
      },
    };
  }

  state = {
    username: "",
  };

  render() {
    return (
      <View model={kinds.wrapper}>
        <View model={kinds.container}>
          <View model={kinds.important}>
            <View model={kinds.fieldContainer}>
              <Textual content model={kinds.label}>Enter your username</Textual content>
              <TextInput
                onChangeText={(username) => this.setState({ username })}
                model={kinds.textInput}
              />
            </View>

            <Button title="Login" shade="#0064e1" onPress={this.login} />

            <TouchableOpacity onPress={this.goToForgotPassword}>
              <View model={kinds.heart}>
                <Textual content model={kinds.link_text}>Forgot Password</Textual content>
              </View>
            </TouchableOpacity>
          </View>
        </View>
      </View>
    );
  }

  
}


const kinds = StyleSheet.create({
  wrapper: {
    flex: 1,
  },
  container: {
    flex: 1,
    alignItems: "heart",
    justifyContent: "heart",
    padding: 20,
  },
  fieldContainer: {
    marginTop: 20,
  },
  label: {
    fontSize: 16,
  },
  textInput: {
    top: 40,
    marginTop: 5,
    marginBottom: 10,
    borderColor: "#ccc",
    borderWidth: 1,
    backgroundColor: "#eaeaea",
    padding: 5,
  },
});

Right here’s the login code. This merely shops the username to native storage and navigates the consumer to the tabbed screens:

login = async () => {
  const { username } = this.state;
  if (username) {
    await AsyncStorage.setItem("username", username);
    goToTabs(world.icons, username);
  }
};

Lastly, right here’s the code for navigating to a different display by way of stack navigation. Merely name the Navigation.push() methodology and cross within the ID of the present display as the primary argument, and the display you wish to navigate to because the second. The title ought to be the identical one you used once you referred to as Navigation.registerComponent() within the navigation.js file earlier:

goToForgotPassword = () => {
  Navigation.push(this.props.componentId, {
    part: {
      title: "ForgotPasswordScreen",
    },
  });
};

ForgotPassword Display

forgot password screen

As talked about earlier, this display is solely used as a filler to reveal stack navigation. Make it possible for the topBar is ready to seen, as a result of it’s the place the again button for going again to the Login display is situated:


import React, { Part } from "react";
import { View, Textual content, TextInput, Button, StyleSheet } from "react-native";

export default class ForgotPassword extends Part {
  static get choices() {
    return {
      topBar: {
        seen: true, 
        title: {
          textual content: "Forgot Password",
        },
      },
    };
  }

  state = {
    e mail: "",
  };

  render() {
    return (
      <View model={kinds.wrapper}>
        <View model={kinds.container}>
          <View model={kinds.important}>
            <View model={kinds.fieldContainer}>
              <Textual content model={kinds.label}>Enter your e mail</Textual content>
              <TextInput
                onChangeText={(e mail) => this.setState({ e mail })}
                model={kinds.textInput}
              />
            </View>

            <Button
              title="Ship E mail"
              shade="#0064e1"
              onPress={this.sendEmail}
            />
          </View>
        </View>
      </View>
    );
  }

  
  sendEmail = async () => {};
}


const kinds = StyleSheet.create({
  wrapper: {
    flex: 1,
  },
  container: {
    flex: 1,
    alignItems: "heart",
    justifyContent: "heart",
    padding: 20,
  },
  fieldContainer: {
    marginTop: 20,
  },
  label: {
    fontSize: 16,
  },
  textInput: {
    top: 40,
    marginTop: 5,
    marginBottom: 10,
    borderColor: "#ccc",
    borderWidth: 1,
    backgroundColor: "#eaeaea",
    padding: 5,
  },
});

You may also have a separate button for going again to the earlier display. All it’s important to do is name the Navigation.pop() methodology:

Navigation.pop(this.props.componentId);

Residence Display

home screen

The Residence display is the default display for the tabbed navigation, so it’s what the consumer will see by default once they log in. This display exhibits the consumer’s title that was handed as a navigation prop in addition to a button for logging out. Clicking the logout button will merely delete the username from native storage and navigate the consumer again to the login display:


import React, { Part } from "react";
import { View, Textual content, Button, StyleSheet } from "react-native";
import Icon from "react-native-vector-icons/FontAwesome";
Icon.loadFont();

import AsyncStorage from "@react-native-async-storage/async-storage";

import { goToLogin } from "../../navigation";

export default class Residence extends Part {
  render() {
    const { username } = this.props;
    return (
      <View model={kinds.container}>
        <Textual content model={kinds.textual content}>Hello {username}!</Textual content>
        <Button onPress={this.logout} title="Logout" shade="#841584" />
      </View>
    );
  }
  

  logout = async () => {
    await AsyncStorage.removeItem("username");
    goToLogin();
  };
}

const kinds = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "heart",
    alignItems: "heart",
  },
  textual content: {
    fontSize: 18,
    fontWeight: "daring",
  },
});

In case you’re questioning how we acquired entry to the username, we’ve handed it as a navigation prop from the navigation file earlier:


{
  part: {
    title: "HomeScreen",
    choices: {
      ...
    },

    
    passProps: {
      username
    },

  }
},

Gallery Display

gallery screen

The Gallery display is only a filler display so we gained’t be delving an excessive amount of into it. Mainly, it simply exhibits a photograph gallery UI:


import React, { Part } from "react";
import {
  View,
  Textual content,
  FlatList,
  Picture,
  Dimensions,
  StyleSheet,
} from "react-native";

const { width } = Dimensions.get("window");
const base_width = width / 2;

const photos = [
  {
    id: 1,
    src: require("../images/blake-richard-verdoorn-20063-unsplash.jpg"),
  },
  {
    id: 2,
    src: require("../images/casey-horner-487085-unsplash.jpg"),
  },
  {
    id: 3,
    src: require("../images/sacha-styles-XK7thML3zEQ-unsplash.jpg"),
  },
  {
    id: 4,
    src: require("../images/eberhard-grossgasteiger-1036384-unsplash.jpg"),
  },
  {
    id: 5,
    src: require("../images/justin-kauffman-449060-unsplash.jpg"),
  },
  {
    id: 6,
    src: require("../images/vincent-guth-182001-unsplash.jpg"),
  },
];

export default class Gallery extends Part {
  render() {
    return (
      <View model={kinds.container}>
        <FlatList
          information={photos}
          keyExtractor={(merchandise, index) => merchandise.id.toString()}
          numColumns={2}
          renderItem={this.renderImage}
        />
      </View>
    );
  }
  

  renderImage = ({ merchandise }) => {
    return (
      <Picture supply={merchandise.src} model={{ width: base_width, top: 250 }} />
    );
  };
}

const kinds = StyleSheet.create({
  container: {
    flex: 1,
  },
});

Be aware that you simply’ll must copy the photographs from our repo, or change them with photos of your individual.

Feed Display

feed screen

Similar to the Gallery display, the Feed display can also be a filler. It merely exhibits a information feed UI:


import React, { Part } from "react";
import {
  View,
  Textual content,
  FlatList,
  Picture,
  TouchableOpacity,
  StyleSheet,
} from "react-native";

const news_items = [
  {
    id: 1,
    title: "The HTML Handbook",
    summary:
      "HTML is the foundation of the marvel called the Web. Discover all you need to know about it in this handy handbook!",
    image: require("../images/amanda-phung-1281331-unsplash.jpg"),
  },
  {
    id: 2,
    title: "Angular RxJs In-Depth",
    summary:
      "In this tutorial, we'll learn to use the RxJS 6 library with Angular 6 or Angular 7...",
    image: require("../images/daniil-silantev-318853-unsplash.jpg"),
  },
  {
    id: 3,
    title: "How to Create Code Profiles in VS Code",
    summary:
      "This post piggybacks off of the work done by @avanslaars who is a fellow instructor at egghead.io....",
    image: require("../images/vincent-van-zalinge-38358-unsplash.jpg"),
  },
];

export default class Feed extends Part {
  render() {
    return (
      <View model={kinds.container}>
        <FlatList
          information={news_items}
          keyExtractor={(merchandise, index) => merchandise.id.toString()}
          renderItem={this.renderItem}
        />
      </View>
    );
  }
  

  renderItem = ({ merchandise }) => {
    return (
      <TouchableOpacity onPress={this.goToNews}>
        <View model={kinds.news_item}>
          <View model={kinds.news_text}>
            <View model={kinds.text_container}>
              <Textual content model={kinds.title}>{merchandise.title}</Textual content>
              <Textual content>{merchandise.abstract}</Textual content>
            </View>
          </View>
          <View model={kinds.news_photo}>
            <Picture supply={merchandise.picture} model={kinds.picture} />
          </View>
        </View>
      </TouchableOpacity>
    );
  };
  

  goToNews = () => {};
}


const kinds = StyleSheet.create({
  container: {
    flex: 1,
  },
  news_item: {
    flex: 1,
    flexDirection: "row",
    paddingRight: 20,
    paddingLeft: 20,
    paddingTop: 20,
    paddingBottom: 20,
    borderBottomWidth: 1,
    borderBottomColor: "#E4E4E4",
  },
  news_text: {
    flex: 2,
    flexDirection: "row",
    padding: 15,
  },
  title: {
    fontSize: 28,
    fontWeight: "daring",
    shade: "#000",
    fontFamily: "georgia",
  },
  news_photo: {
    flex: 1,
    justifyContent: "heart",
    alignItems: "heart",
  },
  picture: {
    width: 120,
    top: 120,
  },
});

Operating the App

At this level, it is best to be capable to run the app. Begin by operating the Metro Bundler:

npx react-native begin

Then run the app in your machine or simulator:

npx react-native run-android
npx react-native run-ios

Check out the app and see if it performs higher than React Navigation (for those who’ve used it earlier than).

Conclusion and Subsequent Steps

On this tutorial, you realized the way to use the React Native Navigation library. Particularly, you realized the way to arrange React Native Navigation and use the stack and tab navigation. You additionally realized the way to load icons from React Native Vector Icons as a substitute of utilizing picture icons.

As a subsequent step, you would possibly wish to take a look at how animations may be personalized, the way to implement a facet menu navigation, or view the examples of various structure sorts.

Should you’re nonetheless not sure about which navigation library to make use of to your subsequent mission, you’ll want to take a look at this publish: “React Navigation vs. React Native Navigation: Which is best for you?

Yow will discover the supply code of the pattern app on this GitHub repo.

Click to comment

Leave a Reply

Your email address will not be published. Required fields are marked *