Pass Data between Pages in React native

Im new to react native and I'm stuck at following.

Im new to react native and I'm stuck at following.

Im performing navigation (when clicked on alert view button) using the code below.

const {navigation} = this.props.navigation;
…
.
.
 { text: 'Done', onPress:() => {
              navigate.push(HomeScreen);}

How can I pass data to another Page in React native? Can I declare the parameter global and just assign to it?

What would be the correct way of performing this and how would I go about it?

Learn how to use the React Native Navigation Library

Learn how to use the React Native Navigation Library

In this tutorial, you'll learn how to use the React Native Navigation library. Learn how to set up React Native Navigation and use the stack and tab navigation. Learn how to load icons from React Native Vector Icons instead of using image icons.

One of the most important aspects of React Native app development is the navigation. It’s what allows users to get to the pages they’re looking for. That’s why it’s important to choose the best navigation library to suit your needs.

If your app has a lot of screens with relatively complex UI, it might be worth exploring React Native Navigation instead of React Navigation. This is because there will always be performance bottlenecks with React Navigation, since it works off the same JavaScript thread as the rest of the app. The more complex your UI, the more data has to be passed to that bridge, which can potentially slow it down.

In this tutorial, we’ll be looking at the React Native Navigation library by Wix, an alternative navigation library for those who are looking for a smoother navigation performance for their React Native apps.

Prerequisites

Knowledge of React and React Native is required to follow this tutorial. Prior experience with a navigation library such as React Navigation is optional.

App Overview

In order to demonstrate how to use the library, we’ll be creating a simple app that uses it. The app will have five screens in total:

  • Initialization: this serves as the initial screen for the app. If the user is logged in, it will automatically navigate to the home screen. If not, the user is navigated to the login screen.
  • Login: this allows the user to log in so they can view the home, gallery, and feed. To simplify things, the login will just be mocked; no actual authentication code will be involved. From this screen, the user can also go to the forgot-password screen.
  • ForgotPassword: a filler screen, which asks for the user’s email address. This will simply be used to demonstrate stack navigation.
  • Home: the initial screen that the user will see when they log in. From here, they can also navigate to either the gallery or feed screens via a bottom tab navigation.
  • Gallery: a filler screen which shows a photo gallery UI.
  • Feed: a filler screen which shows a news feed UI.

Here’s what the app will look like:

You can find the source code of the sample app on this GitHub repo.

Bootstrapping the App

Let’s start by generating a new React Native project:

react-native init RNNavigation --version [email protected]

Note: we’re using a slightly older version of React Native, because React Native Navigation doesn’t work well with later versions of React Native. React Native Navigation hasn’t really kept up with the changes in the core of React Native since version 0.58. The only version known to work flawlessly with React Native is the version we’re going to use. If you check the issues on their repo, you’ll see various issues on version 0.58 and 0.59. There might be workarounds on those two versions, but the safest bet is still version 0.57.

As for React Native version 0.60, the core team has made a lot of changes. One of them is the migration to AndroidX, which aims to make it clearer which packages are bundled with the Android operating system. This essentially means that if a native module uses any of the old packages that got migrated to the new androidx.* package hierarchy, it will break. There are tools such as jetifier, which allows for migration to AndroidX. But this doesn’t ensure React Native Navigation will work.

Next, install the dependencies of the app:

  • react-native-navigation — the navigation library that we’re going to use.
  • @react-native-community/async-storage — for saving data to the app’s local storage.
  • react-native-vector-icons — for showing icons for the bottom tab navigation.
yarn add react-native-navigation @react-native-community/async-storage react-native-vector-icons

In the next few sections, we’ll be setting up the packages we just installed.

Setting up React Native Navigation

First, we’ll set up the React Native Navigation library. The instructions that we’ll be covering here are also in the official documentation. Unfortunately, it’s not written in a very friendly way for beginners, so we’ll be covering it in more detail.

Note: the demo project includes an Android and iOS folders as well. You can use those as a reference if you encounter any issues with setting things up.

Since the name of the library is very long, I’ll simply refer to it as RNN from now on.

Android Setup

In this section, we’ll take a look at how you can set up RNN for Android. Before you proceed, it’s important to update all the SDK packages to the latest versions. You can do that via the Android SDK Manager.

settings.gradle

Add the following to your android/settings.gradle file:

include ':react-native-navigation'
project(':react-native-navigation').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-navigation/lib/android/app/')

Gradle Wrapper Properties

In your android/gradle/wrapper/gradle-wrapper.properties, update Gradle’s distributionUrl to use version 4.4 if it’s not already using it:

distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip

build.gradle

Next, in your android/build.gradle file, add mavenLocal() and mavenCentral() under buildscript -> repositories:

buildscript {
    repositories {
      google()
      jcenter()

      // add these:
      mavenLocal()
      mavenCentral()
    }
}

Next, update the classpath under the buildscript -> dependencies to point out to the Gradle version that we need:

buildscript {
  repositories {
    ...
  }

  dependencies {
    classpath 'com.android.tools.build:gradle:3.0.1'
  }

}

Under allprojects -> repositories, add mavenCentral() and JitPack. This allows us to pull the data from React Native Navigation’s JitPack repository:

allprojects {
allprojects {

  repositories {
    mavenLocal()
    google()
    jcenter()
    mavenCentral() // add this
    maven { url 'https://jitpack.io' } // add this
  }

}

Next, add the global config for setting the build tools and SDK versions for Android:

allprojects {
  ...
}

ext {
    buildToolsVersion = "27.0.3"
    minSdkVersion = 19
    compileSdkVersion = 26
    targetSdkVersion = 26
    supportLibVersion = "26.1.0"
}

Lastly, we’d still want to keep the default react-native run-android command when compiling the app, so we have to set Gradle to ignore other flavors of React Native Navigation except the one we’re currently using (reactNative57_5). Ignoring them ensures that we only compile the specific version we’re depending on:

ext {
 ...
}

subprojects { subproject ->
    afterEvaluate {
        if ((subproject.plugins.hasPlugin('android') || subproject.plugins.hasPlugin('android-library'))) {
            android {
                variantFilter { variant ->
                    def names = variant.flavors*.name
                    if (names.contains("reactNative51") || names.contains("reactNative55") || names.contains("reactNative56") || names.contains("reactNative57")) {
                        setIgnore(true)
                    }
                }
            }
        }
    }
}

Note: there are four other flavors of RNN that currently exist. These are the ones we’re ignoring above:

  • reactNative51
  • reactNative55
  • reactNative56
  • reactNative57

android/app/build.gradle

On your android/app/build.gradle file, under android -> compileOptions, make sure that the source and target compatibility version is 1.8:

android {
  defaultConfig {
    ...
  }

  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }
}

Then, in your dependencies, include react-native-navigation as a dependency:

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
    implementation "com.facebook.react:react-native:+"
    implementation project(':react-native-navigation') // add this
}

Lastly, under android -> defaultConfig, set the missingDimensionStrategy to reactNative57_5. This is the version of RNN that’s compatible with React Native 0.57.8:

defaultConfig {
  applicationId "com.rnnavigation"
  minSdkVersion rootProject.ext.minSdkVersion
  targetSdkVersion rootProject.ext.targetSdkVersion
  missingDimensionStrategy "RNN.reactNativeVersion", "reactNative57_5" // add this
  versionCode 1
  versionName "1.0"
  ndk {
    abiFilters "armeabi-v7a", "x86"
  }
}

MainActivity.java

On your app/src/main/java/com/rnnavigation/MainActivity.java file, extend from RNN’s NavigationActivity instead:

package com.rnnavigation;

// import com.facebook.react.ReactActivity;
import com.reactnativenavigation.NavigationActivity;

// public class MainActivity extends ReactActivity {
public class MainActivity extends NavigationActivity {
  // remove all code inside
}

Since we’ve removed the default code that React Native uses, we’ll no longer need to register the main component as you’ll see later in the Building the App section:

// index.js
import { AppRegistry } from "react-native";
import App from "./App";
import { name as appName } from "./app.json";

AppRegistry.registerComponent(appName, () => App);

MainApplication.java

Next, you also need to update the app/src/main/java/com/rnnavigation/MainApplication.java file to inherit from RNN’s class instead. Start by importing RNN’s classes:

import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;

// add these
import com.reactnativenavigation.NavigationApplication;
import com.reactnativenavigation.react.NavigationReactNativeHost;
import com.reactnativenavigation.react.ReactGateway;

Next, inherit from RNN’s NavigationApplication class instead:

// public class MainApplication extends Application implements ReactApplication {
public class MainApplication extends NavigationApplication {

}

Lastly, completely replace the contents of the class with the following:

@Override
protected ReactGateway createReactGateway() {
  ReactNativeHost host = new NavigationReactNativeHost(this, isDebug(), createAdditionalReactPackages()) {
    @Override
    protected String getJSMainModuleName() {
      return "index";
    }
  };
  return new ReactGateway(this, isDebug(), host);
}

@Override
public boolean isDebug() {
  return BuildConfig.DEBUG;
}

protected List<ReactPackage> getPackages() {
  return Arrays.<ReactPackage>asList(

  );
}

@Override
public List<ReactPackage> createAdditionalReactPackages() {
  return getPackages();
}

The only thing that might look familiar to you in the above code is the getPackages() method. Just like in the standard React Native project, this is where you can initialize the classes of your native dependencies.

iOS Setup

In this section, we’ll set up RNN for iOS. Before you proceed, it’s important that you have updated Xcode to the latest available version. This helps to avoid potential errors that comes with outdated Xcode modules.

First, open the ios/RNNavigation.xcodeproj file with Xcode. This is the corresponding Xcode project for the app.

Once opened, in your project navigator (left pane where the project files are listed), right-click on Libraries -> Add files to RNNavigation. On the file picker that shows up, go to the node_modules/react-native-navigation/lib/ios directory and select the ReactNativeNavigation.xcodeproj file:

Next, click on RNNavigation in the TARGETS row and click on the Build Phases tab. From there, look for Link Binary With Libraries, expand it, then click on the button for adding a new item:

On the modal window that pops up, search for the libReactNativeNavigation.a file, select it, and then click on the Add button:

Next, open the AppDelegate.m file and replace its contents with the following. This is basically the entry point of the React Native app (similar to the MainApplication.java in Android). We’re updating it so that it uses RNN instead:

#import "AppDelegate.h"

 #import <React/RCTBundleURLProvider.h>
 #import <React/RCTRootView.h>
 #import <ReactNativeNavigation/ReactNativeNavigation.h>

 @implementation AppDelegate

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
 {
     NSURL *jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
     [ReactNativeNavigation bootstrap:jsCodeLocation launchOptions:launchOptions];

     return YES;
 }

 @end

That’s pretty much it for the linking of RNN to iOS. But if you encounter any issues, you’ll probably have to follow the next section as well.

Common Issues

In this section, we’ll go through some of the most common issues that you may encounter when linking RNN to iOS.

When you’ve edited and saved the AppDelegate.m file, you’ll probably encounter this issue. This will appear in red squiggly lines in the file itself:

! 'RCTBundleURLProvider.h' file not found

This happens because the React scheme is missing from your project.

To make it available, execute the following commands inside your project’s root directory (RNNavigation):

npm install -g react-native-git-upgrade
react-native-git-upgrade

This will add the missing files to your project.

Once that’s done, go to Product -> Scheme -> Manage Schemes, then click on the + button to add a new scheme. From the Target dropdown, select React, then click OK to add it:

Once added, make sure both the Show and Shared checkboxes are checked:

The next issue that you might encounter is this:

'ReactNativeNavigation/ReactNativeNavigation.h' file not found.

This means it couldn’t find the said file in your project’s path. To solve it, click on RNNavigation in the TARGETS. Then click on Build Settings and below it, make sure the All and Combined is used as a filter, then look for header search in the search bar. Double-click on Header Search Paths, click on the + button, and add $(SRCROOT)/../node_modules/react-native-navigation/lib/ios as a path:

Setting up AsyncStorage and Vector Icons

The process of setting up AsyncStorage and Vector Icons is very similar to the install processes outlined above, so I’ll just link to the official documentation.

Here are the instructions for AsyncStorage:

  • Android Setup.
  • iOS Setup. Be sure to follow the non-pods version, as that’s easier to get set up with. The non-pods (short for non CocoaPods) is one that doesn’t use CocoaPods as a dependency manager. The main file of the native module will simply be linked as a library. That’s basically the same thing we did with the libReactNativeNavigation.a file earlier.

And here are the instructions for Vector Icons. To simplify things, just follow the instructions for adding the whole Fonts folder to the Xcode project:

Note: you can always check the GitHub repo if you get lost.

Okay, so that was a lot of manual setup. If you really need RNN in your project, then it’s a necessity. Every time you introduce a new dependency that has a native link, you have to follow the instructions for manually linking it. react-native link won’t work, because we’ve replaced ReactApplication with NavigationApplication in MainApplication.java, so the linking is now done a little bit differently. You can probably get away with still running react-native link if you know exactly what it’s doing and you can completely undo what it’s done. But it’s safer to just follow the manual linking instructions.

Building the App

Now we’re ready to finally start building the app.

index.js

First, open the existing index.js on the root of the project directory and replace its contents with the following. This serves as the entry point of the app. If you noticed, we no longer have to register the main app component using React Native’s AppRegistry. Instead, we’re now using RNN’s registerComponent() method. This has to do with the updates we did earlier to the MainActivity.java and AppDelegate.m file.

The registerComponent() method accepts the screen’s unique name and the component to use to render the screen. Once it’s registered, we call the registerAppLaunchedListener() method to set the root screen for the app to LoadingScreen. This is similar to what the AppRegistry.registerComponent() does:

// index.js
import { Navigation } from "react-native-navigation";
import Icon from "react-native-vector-icons/FontAwesome";

import Loading from "./src/screens/Loading"; // the loading screen

import "./loadIcons"; // file for loading the icons to be used in the bottom tab navigation

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

Navigation.events().registerAppLaunchedListener(() => {
  // set the root component
  Navigation.setRoot({
    root: {
      component: {
        name: "LoadingScreen"
      }
    }
  });
});

Loading Screen

The loading screen serves as the entry point of the app. But you may be asking why a loading screen? Why not a login screen instead? This is because our sample app has a mock login system, meaning that we first have to determine if a user is already logged in or not. Using a loading screen works better than having to initially load a login screen only to find out that a user is already logged in, so we then have to navigate them to the home screen.

Start by creating a src/screens/Loading.js file and add the following:

// src/screens/Loading.js
import React, { Component } from "react";
import { View, Text, ActivityIndicator, StyleSheet } from "react-native";

import { goToLogin, goToTabs } from "../../navigation"; // import the functions for loading either the login screen or the tabs screen (shows home screen by default)

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

Next, create the component itself. When the component is mounted, we try to get the username of the logged-in user from local storage. If it exists, then we navigate the user to the tabs, otherwise to the login screen:

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

  render() {
    // show loading indicator
    return (
      <View style={styles.container}>
        <ActivityIndicator size="large" color="#0000ff" />
      </View>
    );
  }
}
//

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

In the above code, notice we’re passing global.icons as an argument to the goToTabs() function. That value is being set in the loadIcons.js that we imported from the index.js file earlier. Its job is to load the icons to be used for the bottom tabs, as you’ll see later.

navigation.js

This is where we register all the screens of the app and declare our navigation functions for navigating between the login screen and the tabbed screens:

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

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

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

The goToLogin() function creates a stack navigation. In RNN, these navigation types are called “Layouts”. Currently, there are only three: stacks, tabs, and drawers. We’ll only use stack and tabs in this tutorial, but here’s a brief overview of each one:

  • Stack: each new screen you navigate to is laid out on top of the current one. So when you go back to the previous screen, the idea is to simply “pop” the current screen out of the stack. We’ll be using the stack navigation to navigate between the Login screen and ForgotPassword screen.
  • Tab: each screen can be accessed via a bottom tab navigation. Each tab has both icon and text on it to describe the screen it navigates the user to. This type of navigation is commonly used if there are two or more main screens within the app. Having a bottom tab navigation allows for easy access between those screens. We’ll be using the tab navigation to navigate between the Home, Gallery, and Feed screens.
  • Drawer: also called the side menu. This is called drawer because it’s commonly hidden within a hamburger icon and it only shows the menu under it when clicked on.

Going back to the code, we’ve only added the Login screen as a child of stack navigation, even though the ForgotPassword screen is part of it as well. As mentioned earlier, we’ll be using stack navigation to navigate between the Login screen and the ForgotPassword screen. Yet we’ve only added the Login screen here as a child. Adding it will simply make it as the default screen for the stack. In a stack navigation, you should only add the initial screen for that specific stack as the child, as you’ll see later.

The minimum requirement for a child is to add the name property for each screen. This is the name of the screen to be used for rendering. This should be the same name you used when you registered the component:

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

Note: supplying an ID for the navigation isn’t required, but it’s good practice—especially if you know that you’ll start using the same layout type multiple times in your app.

Next, add the goToTabs() function. Unlike the previous function, this accepts two arguments: icons and username. icons is the array of icons to be used for the individual tabs, while username is the username of the user who logged in. This time, we’re using the bottomTabs navigation. As the name suggests, this allows the user to navigate between screens using bottom tabs. You can create bottom tabs using the following format:

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

export const goToTabs = (icons, username) => {
  Navigation.setRoot({
    root: {
      bottomTabs: {
        // create a bottom tabs navigation

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

              // pass the username as a navigation prop to the Home screen
              passProps: {
                username
              }
            }
          },

          {
            component: {
              name: "GalleryScreen",
              options: {
                bottomTab: {
                  fontSize: 11,
                  text: "Gallery",
                  icon: icons[1],
                  iconColor,
                  selectedIconColor
                }
              }
            }
          },

          {
            component: {
              name: "FeedScreen",
              options: {
                bottomTab: {
                  fontSize: 11,
                  text: "Feed",
                  icon: icons[2],
                  iconColor,
                  selectedIconColor
                }
              }
            }
          }
        ]
      }
    }
  });
};

As you’ve seen from the code above, this pretty much uses the same format as the stack navigation. The only difference is that, this time, we’re also specifying an options property for the individual bottomTab. These options are mostly used for configuring the styles of the individual tab. They’re self-explanatory, so I won’t go into detail, but I just want to explain the icon property. By default, this accepts a local image that’s required by a require('./path/to/image.png') call. But since we’ve already installed Vector Icons, we might as well use it as the icon source instead. The only problem is that we can’t really supply a React component as the value for the icon because it expects a resource. The icons parameter accepts an array of icon resource and that’s what we’re using instead. You’ll learn how we’re loading those in the next section.

Note: you can find more styling options for bottom tabs in the official documentation for Styling. Just look for bottomTabs or bottomTab.

loadIcons.js

Here’s the code for the loadIcons file that we imported in the index.js file earlier. This uses icons from FontAwesome. Here, we’re using the getImageSource() method from Vector Icons to get the actual image resource. This allows us to use it as an icon for the bottom tabs:

// loadIcons.js
import Icon from "react-native-vector-icons/FontAwesome";

(function() {
  Promise.all([
    Icon.getImageSource("home", 11), // name of icon, size
    Icon.getImageSource("image", 11),
    Icon.getImageSource("rss-square", 11)
  ]).then(async values => {
    global.icons = values; // make it available globally so we don't need to load it again
  });
})();

Login Screen

The Login screen is the default screen that the user will see if they aren’t logged in. From here, they can log in by entering their username or they can click on forgot password to view the screen for resetting their password. As mentioned earlier, all of this is just mocked and no actual authentication code is used:

// src/screens/Login.js
import React, { Component } from "react";
import { Navigation } from "react-native-navigation";
import {
  View,
  Text,
  TextInput,
  Button,
  TouchableOpacity,
  StyleSheet
} from "react-native";
import AsyncStorage from "@react-native-community/async-storage";

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

export default class Login extends Component {
  static get options() {
    return {
      topBar: {
        visible: false // need to set this because screens in a stack navigation have a header by default
      }
    };
  }

  state = {
    username: ""
  };

  render() {
    return (
      <View style={styles.wrapper}>
        <View style={styles.container}>
          <View style={styles.main}>
            <View style={styles.fieldContainer}>
              <Text style={styles.label}>Enter your username</Text>
              <TextInput
                onChangeText={username => this.setState({ username })}
                style={styles.textInput}
              />
            </View>

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

            <TouchableOpacity onPress={this.goToForgotPassword}>
              <View style={styles.center}>
                <Text style={styles.link_text}>Forgot Password</Text>
              </View>
            </TouchableOpacity>
          </View>
        </View>
      </View>
    );
  }

  // next: add login code
}
//

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

Here’s the login code. This simply stores the username to local storage and navigates the user to the tabbed screens:

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

Lastly, here’s the code for navigating to another screen via stack navigation. Simply call the Navigation.push() method and pass in the ID of the current screen as the first argument, and the screen you want to navigate to as the second. The name should be the same one you used when you called Navigation.registerComponent() in the navigation.js file earlier:

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

ForgotPassword Screen

As mentioned earlier, this screen is simply used as a filler to demonstrate stack navigation. Make sure that the topBar is set to visible, because it’s where the back button for going back to the Login screen is located:

// src/screens/ForgotPassword.js
import React, { Component } from "react";
import { View, Text, TextInput, Button, StyleSheet } from "react-native";

export default class ForgotPassword extends Component {
  static get options() {
    return {
      topBar: {
        visible: true, // visible
        title: {
          text: "Forgot Password"
        }
      }
    };
  }

  state = {
    email: ""
  };

  render() {
    return (
      <View style={styles.wrapper}>
        <View style={styles.container}>
          <View style={styles.main}>
            <View style={styles.fieldContainer}>
              <Text style={styles.label}>Enter your email</Text>
              <TextInput
                onChangeText={email => this.setState({ email })}
                style={styles.textInput}
              />
            </View>

            <Button
              title="Send Email"
              color="#0064e1"
              onPress={this.sendEmail}
            />
          </View>
        </View>
      </View>
    );
  }

  //
  sendEmail = async () => {};
}
//

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

You can also have a separate button for going back to the previous screen. All you have to do is call the Navigation.pop() method:

Navigation.pop(this.props.componentId);

Home Screen

The Home screen is the default screen for the tabbed navigation, so it’s what the user will see by default when they log in. This screen shows the user’s name that was passed as a navigation prop as well as a button for logging out. Clicking the logout button will simply delete the username from local storage and navigate the user back to the login screen:

// src/screens/Home.js
import React, { Component } from "react";
import { View, Text, Button, StyleSheet } from "react-native";
import Icon from "react-native-vector-icons/FontAwesome";
import AsyncStorage from "@react-native-community/async-storage";

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

export default class Home extends Component {
  render() {
    const { username } = this.props;
    return (
      <View style={styles.container}>
        <Text style={styles.text}>Hi {username}!</Text>
        <Button onPress={this.logout} title="Logout" color="#841584" />
      </View>
    );
  }
  //

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

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center"
  },
  text: {
    fontSize: 18,
    fontWeight: "bold"
  }
});

In case you’re wondering how we got access to the username, we’ve passed it as a navigation prop from the navigation file earlier:

// navigation.js
{
  component: {
    name: "HomeScreen",
    options: {
      ...
    },

    // here:
    passProps: {
      username
    },

  }
},

Gallery Screen

The Gallery screen is just a filler screen so we won’t be delving too much into it. Basically, it just shows a photo gallery UI:

// src/screens/Gallery.js
import React, { Component } from "react";
import {
  View,
  Text,
  FlatList,
  Image,
  Dimensions,
  StyleSheet
} from "react-native";

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

const images = [
  {
    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 Component {
  render() {
    return (
      <View style={styles.container}>
        <FlatList
          data={images}
          keyExtractor={(item, index) => item.id.toString()}
          numColumns={2}
          renderItem={this.renderImage}
        />
      </View>
    );
  }
  //

  renderImage = ({ item }) => {
    return (
      <Image source={item.src} style={{ width: base_width, height: 250 }} />
    );
  };
}

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

Feed Screen

Just like the Gallery screen, the Feed screen is also a filler. It simply shows a news feed UI:

// src/screens/Feed.js
import React, { Component } from "react";
import {
  View,
  Text,
  FlatList,
  Image,
  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 Component {
  render() {
    return (
      <View style={styles.container}>
        <FlatList
          data={news_items}
          keyExtractor={(item, index) => item.id.toString()}
          renderItem={this.renderItem}
        />
      </View>
    );
  }
  //

  renderItem = ({ item }) => {
    return (
      <TouchableOpacity onPress={this.goToNews}>
        <View style={styles.news_item}>
          <View style={styles.news_text}>
            <View style={styles.text_container}>
              <Text style={styles.title}>{item.title}</Text>
              <Text>{item.summary}</Text>
            </View>
          </View>
          <View style={styles.news_photo}>
            <Image source={item.image} style={styles.photo} />
          </View>
        </View>
      </TouchableOpacity>
    );
  };
  //

  goToNews = () => {};
}
//

const styles = 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: "bold",
    color: "#000",
    fontFamily: "georgia"
  },
  news_photo: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center"
  },
  photo: {
    width: 120,
    height: 120
  }
});

Running the App

At this point, you should be able to run the app:

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

Try out the app and see if it performs better than React Navigation (if you’ve used it before).

Conclusion and Next Steps

In this tutorial, you learned how to use the React Native Navigation library. Specifically, you learned how to set up React Native Navigation and use the stack and tab navigation. You also learned how to load icons from React Native Vector Icons instead of using image icons.

As a next step, you might want to check out how animations can be customized, how to implement a side menu navigation, or view the examples of different layout types.

React Native Tutorial: Facebook login using React Native FBSDK

React Native Tutorial: Facebook login using React Native FBSDK

In this React Native tutorial, we will show you how to implementing or integrating Facebook login using React Native FBSDK (react-native-fbsdk) library/module. React Native FBSDK is a wrapper around the iOS Facebook SDK and Android Facebook SDK, allowing for Facebook integration in React Native apps

A comprehensive step by step React Native tutorial on implementing Facebook Login using React Native FBSDK including the working example.
Every access to the Native components is provided by Javascript modules. We have focused on the FB login that is the standard of almost all authenticated Mobile apps.

Table of Contents:

  • Setup a Facebook App
  • Install React Native CLI and Create App
  • Install React Native FBSDK (react-native-fbsdk) Module
  • Implements Facebook Login, Logout, and Share
  • Run and Test React Native Facebook Login App

The flow of this React Native FB login is very simple. Just a page with a "Sign in with Facebook" button which after clicking the FB login and successful login it will return with the basic info of your Facebook account. The following tools, frameworks, and modules are required for this tutorial:

  1. React Native
  2. Node.js (NPM or Yarn)
  3. react-native-fbsdk module
  4. React Native Elements
  5. Facebook Developer Dashboard
  6. Android Studio or SDK for Android
  7. XCode for iOS
  8. Terminal (OSX/Linux) or Command Line (Windows)
  9. Text Editor or IDE (We are using VSCode)

Before start to the main steps, make sure that you have installed Node.js and can run npm in the terminal or command line. To check the existing or installed Node.js environment open the terminal/command line then type this command.

node -v
v10.15.1
npm -v
6.11.2
yarn -v
1.10.1
Setup a Facebook App

This step is about to set up or create a Facebook App to get the App ID and secret. Also, set the bundle ID for native iOS and Google Play package names for native Android. To set up or create a Facebook App, go to the Facebook Developers Dashboard. Login with your Facebook developers' account or credentials.

Click the + Add a New App button. Enter the display name (we use MyIonicApp name) then click the Create App ID button. Make sure to use the valid name allowed by Facebook Developers.

After checking the captcha dialog and click submit button, now, you can see App ID and Secret, write it to your notepad.

Click the Facebook Login Set up button.

Choose iOS first then on the iOS wizard scroll down to the bottom to enter iOS bundle ID that will supply on the XCode later.

Select SDK: Cocoapods as a development environment before using Facebook Login for iOS then click the Next button.

Enter iOS bundle ID that will supply on config.xml later (we use "com.djamware.myreactnativeapp") then click save then click the Continue button.

Enabled the Single Sign-On feature then click Save and Next button a few times until the end of the iOS steps. Next, click on the Android tab then click Download Android SDK.

Click the Next button 2 times then fill the Android project package name (we use "com.djamware.myreactnativeapp") and default Android Activity Class name.

Click the save button and this setup will check to the Google Play for the existence of this package name. You can ignore the popup message if there's no package found in the Google Play. Click the Continue button.

As you see, we need to create a Key Hashes. To get the key hashes, especially in development build open the terminal or command line then type this command.

keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64

Enter "android" as the Key Pass.

Enter keystore password:  android
K1IC8IKUNGj8tt2BHTpm11c7uRE=

Copy and paste the Key Hashes like above to the Key Hashes field of the Facebook Android Setup then click save and continue button.

Enabled Single Sign-On then click Next button a few times until the end of the Facebook Android setup.

Install React Native CLI and Create App

This time we will use React Native CLI to create a React Native app because the Firebase Cloud Messaging will use natively. To install it, type this command in your App projects folder.

sudo npm install -g react-native-cli

Then create a React Native App using this command from your project directory.

react-native init ReactNativeFacebook

Next, go to the newly created React App folder and run the React Native app to the simulator.

cd ReactNativeFacebook && react-native run-ios

When a new terminal window opened, go to the React Native project folder then run the Metro bundler server.

cd ~/Apps/ReactNativeFacebook && yarn start

Now, you will see this in the iOS simulator.

Next, we will change the iOS and Android package name or bundle ID to match the Firebase configuration files. For iOS, open the ios/ReactNativeFacebook.xcworkspace file using XCode.

Just change the Bundle Identifier (ours: com.djamware.myreactnativeapp) and it ready to use with the Facebook App. For Android a little tricky, first, change the source folders which previously android/app/src/main/java/com/reactnativefacebook become android/app/src/main/java/com/djamware/myreactnativeapp.

Next, open and edit android/app/src/main/java/com/djamware/myreactnativeapp/MainActivity.java then this package name.

package com.reactnativefacebook;

to

package com.djamware.myreactnativeapp;

Do the same way to android/app/src/main/java/com/djamware/myreactnativeapp/MainApplication.java. Next, open and edit android/app/src/main/AndroidManifest.xml then change this line.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.reactnativefacebook">

To

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.djamware.myreactnativeapp">

Next, open edit android/app/build.gradle then change the application ID to the new package.

android {
    ...
    defaultConfig {
        applicationId "com.djamware.myreactnativeapp"
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode 1
        versionName "1.0"
    }
    ...
}

Next, open and edit android/app/BUCK then change the android_build_config and android_resource package name.

android_build_config(
    name = "build_config",
    package = "com.djamware.myreactnativeapp",
)

android_resource(
    name = "res",
    package = "com.djamware.myreactnativeapp",
    res = "src/main/res",
)

Finally, run this command from the android folder to clean up the Gradle.

cd android
./gradlew clean
Install React Native FBSDK (react-native-fbsdk) Module

To install React Native FBSDK (react-native-fbsdk) module, type this command.

yarn add react-native-fbsdk

or

npm install --save react-native-fbsdk

Next, you need to link this module to the Native iOS and Android using this command.

react-native link react-native-fbsdk

Configure Facebook SDK iOS

To configure the Facebook SDK for iOS, go to the iOS folder then install Cocoapods.

cd ios
pod install

Next, open the ReactNativeFacebook.xcworkspace file using XCode then right-click the Info.plist and select Open As -> Source Code. Add these lines of XML snippets before the closing of element.

CFBundleURLTypes

  
    CFBundleURLSchemes
    
      fb{your-app-id}
    
  

FacebookAppID
{your-app-id}
FacebookDisplayName
{your-app-name}
LSApplicationQueriesSchemes

  fbapi
  fb-messenger-share-api
  fbauth2
  fbshareextension

Change {your-app-id} and {your-app-name} with the Facebook App ID and Name that showed up in the Facebook Developer App Dashboard that previously created. Next, we have to manually add a few Obj-C codes to make Facebook App integration works. Open and edit AppDelegate.m the file then add this import.

#import 

Add FBSDKApplicationDelegate before the return line.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
  RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
                                                   moduleName:@"ReactNativeFacebook"
                                            initialProperties:nil];

  rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];

  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  UIViewController *rootViewController = [UIViewController new];
  rootViewController.view = rootView;
  self.window.rootViewController = rootViewController;
  [self.window makeKeyAndVisible];

  [[FBSDKApplicationDelegate sharedInstance] application:application
                           didFinishLaunchingWithOptions:launchOptions];

  return YES;
}

Also, add this method below didFinishLaunchingWithOptions method.

- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
            options:(NSDictionary *)options {

  BOOL handled = [[FBSDKApplicationDelegate sharedInstance] application:application
                                                                openURL:url
                                                      sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey]
                                                             annotation:options[UIApplicationOpenURLOptionsAnnotationKey]
                  ];
  // Add any custom logic here.
  return handled;
}

To send the Facebook App event to the Facebook App Dashboard analytics add this method.

- (void)applicationDidBecomeActive:(UIApplication *)application {
  [FBSDKAppEvents activateApp];
}

Configure Facebook SDK Android

To configure Facebook SDK for Android, open and edit the main or root Build.gradle then add this mavenCentral() repository to buildscript { repositories {}}.

repositories {
    google()
    jcenter()
    mavenCentral()
}

Next, open and edit android/app/build.gradle then add this dependency inside dependencies {} body.

implementation 'com.facebook.android:facebook-android-sdk:[5,6)'

Next, build this Android app to make the Facebook SDK library installed by type this command inside the android folder.

./gradlew build

Next, to add Facebook App ID to Android app, open and edit android/app/res/values/strings.xml then add this value.

YOUR_FB_ID

Replace YOUR_FB_ID with your Facebook App ID. Next, open and edit android/app/manifests/AndroidManifest.xml then make sure this permission added.


Add Facebook Application ID to the application element.

<application
   android:name=".MainApplication"
   ...>
   ...
   
 
Implements Facebook Login, Logout, and Share

Now, we will implement a Facebook login, logout, and share. First, we need to add React Native Elements to use the nice component for the React Native app. Type this command to install it.

yarn add react-native-elements
yarn add react-native-vector-icons

or

npm i react-native-elements --save
npm i --save react-native-vector-icons

Then link the react-native-vector-icons with the Native iOS and Android app.

react-native link react-native-vector-icons

Next, to implement Facebook login, logout, and share, we will use just a single existing App.js. Open and edit that file then add or modify these imports of React Hooks useState, useEffect, required React Native components, required React Native FBSDK components, and required React Native Elements components.

import React, { useState, useEffect } from 'react';
import {
  Alert,
  SafeAreaView,
  StyleSheet,
  ScrollView,
  View,
  StatusBar,
  Text,
  TouchableHighlight
} from 'react-native';

import {
  Header,
  Colors,
} from 'react-native/Libraries/NewAppScreen';
import { LoginButton, AccessToken, ShareDialog, GraphRequest, GraphRequestManager } from 'react-native-fbsdk';
import { Card, Image } from 'react-native-elements'

Change the generated App constant to this declaration.

const App = () => {
...
}

Declare the required variable using React Hooks useState in the top of App constant body.

const [profile, setProfile] = useState([]);
const [profileImage, setProfileImage] = useState();
const [isLoggedIn, setLoggedIn] = useState(false);

Declare a constant variable as the content for Facebook shares.

const SHARE_LINK_CONTENT = {
  contentType: 'link',
  contentUrl: 'https://www.facebook.com/',
};

Add a function to get Facebook public_profile that put the response to profile and profileImage variables using setProfile and setProfileImage useState.

getPublicProfile = async () => {
  const infoRequest = new GraphRequest(
    '/me?fields=id,name,picture',
    null,
    (error, result) => {
      if (error) {
        console.log('Error fetching data: ' + error.toString());
      } else {
        console.log(result);
        setProfile(result);
        setProfileImage(result.picture.data.url);
      }
    }
  );
  new GraphRequestManager().addRequest(infoRequest).start();
}

Add a function or method to share the link with dialog opened and using the content from the previously declared constant variable.

shareLinkWithDialog = async () => {
  const canShow = await ShareDialog.canShow(SHARE_LINK_CONTENT);
  if (canShow) {
    try {
      const {isCancelled, postId} = await ShareDialog.show(
        SHARE_LINK_CONTENT,
      );
      if (isCancelled) {
        Alert.alert('Share cancelled');
      } else {
        Alert.alert('Share success with postId: ' + postId);
      }
    } catch (error) {
      Alert.alert('Share fail with error: ' + error);
    }
  }
};

Modify the View to implement the UI of Facebook Login, Profile, Share, and Logout.

return (
    
      
      
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={styles.scrollView}>
          
          
            <LoginButton
              onLoginFinished={
                (error, result) => {
                  if (error) {
                    console.log("login has error: " + result.error);
                  } else if (result.isCancelled) {
                    console.log("login is cancelled.");
                  } else {
                    setLoggedIn(true);
                    AccessToken.getCurrentAccessToken().then(
                      (data) => {
                        console.log(data.accessToken.toString());
                        this.getPublicProfile();
                      }
                    )
                  }
                }
              }
              onLogoutFinished={() => {
                console.log("logout.");
                setLoggedIn(false);
              }}/>
            { isLoggedIn && <Card
                title={profile.name}>
                <Image
                  source={{ uri: profileImage }}
                  style={{ width: 50, height: 50 }}
                />
                
                  Share link with ShareDialog
                
              
            }
          
        
      
    
  );
};
Run and Test React Native Facebook Login App

To run the whole React Native Facebook Login App, first, re-link again the React Native to React Native FBSDK.

react-native unlink react-native-fbsdk
react-native link react-native-fbsdk

Run the React Native app to the Android device using this command. Make sure the Android device connected using USB cable and USB Debugging is enabled so it can be detected using ADB command.

react-native run-android

The new terminal tab will open then run the Metro Bundler after going to the root of the project folder.

cd ~/Apps/ReactNativeFacebook && yarn start

For the iOS, we can open the ios/ReactNativeFacebook.xcworkspace from the XCode then use the valid provisioning profile signing then run the iOS app from there while the Metro Bundler runs from the terminal.

That it's, the React Native Facebook login app. You can find the full source from our GitHub.

6 Tools for Debugging React Native

 6 Tools for Debugging React Native

In the React Native world, debugging may be done in different ways and with different tools, since React Native is composed of different environments (iOS and Android), which means there’s an assortment of problems and a variety of tools needed for debugging. In this brief guide, we’ll explore the 6 tools for debugging React Native.

Debugging is an essential part of software development. It’s through debugging that we know what’s wrong and what’s right, what works and what doesn’t. Debugging provides the opportunity to assess our code and fix problems before they’re pushed to production.

In the React Native world, debugging may be done in different ways and with different tools, since React Native is composed of different environments (iOS and Android), which means there’s an assortment of problems and a variety of tools needed for debugging.

Thanks to the large number of contributors to the React Native ecosystem, many debugging tools are available. In this brief guide, we’ll explore the most commonly used of them, starting with the Developer Menu.

Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it. — Brian W. Kernighan

1. The Developer Menu

The in-app developer menu is your first gate for debugging React Native, it has many options which we can use to do different things. Let’s break down each option.

  • Reload: reloads the app
  • Debug JS Remotely: opens a channel to a JavaScript debugger
  • Enable Live Reload: makes the app reload automatically on clicking Save
  • Enable Hot Reloading: watches for changes accrued in a changed file
  • Toggle Inspector: toggles an inspector interface, which allows us to inspect any UI element on the screen and its properties, and presents and interface that has other tabs like networking, which shows us the HTTP calls, and a tab for performance.
2. YellowBoxes and RedBoxes

RedBoxes are used to display errors. Every time an app throws an error, it will display a RedBox and the description of the error. You can display it any time by writing console.error. But it doesn’t work in the production, meaning that if an error happens in that environment, the app will crash and stop running.

The RedBox is your friend. One of the helpful things about it is that it displays the error and gives you the suggestions on how to fix it, which you won’t find in the console. For example, I’ll frequently write a style property that’s not supported by React Native, or a property that’s used for a specific element—such as setting backroundImage for the View element. The Redbox will throw an error, but it will also show the list of supported style properties that you can apply to the View.

YellowBoxes are used to display warnings. You can disable them by adding line of code shown below inside index.js in the root directory of your app. But that’s not recommended, as YellowBoxes are very useful. They warn you about things like performance issues and deprecated code. You can use the YellowBox element from react-native to display a specific warning.

import {YellowBox} from 'react-native';
YellowBox.ignoreWarnings(['Warning: ...']);

Most YellowBox warnings are related to some bad practice in your code. For example, you might get a warning that you have an eventListener that you aren’t removing when the component unmounts, or that you have deprecated features and dependencies like this:

warning: ViewPagerAndroid has been extracted from react-native core and will be removed in a future release. It can now be installed and imported from '@react-native-community/viewpager' instead of 'react-native'. See https://github.com/react-native-community/react-native-viewpager

Fixing these issues will prevent many bugs and will improve the quality of your code.

You can always learn more about debugging React Native in the official docs.

3. Chrome’s DevTools

Chrome is possibly the first tool you’d think of for debugging React Native. It’s common to use Chrome’s DevTools to debug web apps, but we can also use them to debug React Native since it’s powered by JavaScript.

To use Chrome’s DevTools with React Native, first make sure you’re connected to the same Wi-Fi, then press command + R if you’re using macOS, or Ctrl + M on Windows/Linux. When the developer menu appears, choose Debug Js Remotely. This will open the default JS debugger.

Then check this address http://localhost:8081/debugger-ui/ in Chrome. You should see this page:

You may have to do some troubleshooting on Android.

To solve this problem, make sure your your machine and the device are connected on the same Wi-Fi, and then add android:usesCleartextTraffic="true" to android/app/src/main/AndroidManifest.xml. If this doesn’t work for you, check out these links for other solutions:

After you have successfully connected to Chrome, you can simply toggle the Chrome inspector.

Then take a look at the logs of your React Native app. Also have a look through the other features offered by Chrome’s DevTools, and use them with React Native as you do with any Web app.

One of the limitations of using Chrome’s DevTools with React Native is that you can’t debug the styles and edit the style properties as you usually do when you debug web apps. It’s also limited in comparison with React’s devtools when inspecting React’s component hierarchy.

4. React Developer Tools

To debug React Native using React’s Developer Tools, you need to use the desktop app. You can install it globally or locally in your project by just running this following command:

yarn add react-devtools

Or npm:

npm install react-devtools --save

Then start the app by running yarn react-devtools, which will launch the app.

React’s Developer Tools may be the best tool for debugging React Native for these two reasons:

  • It allows for debugging React components.
  • It makes it possible to debug styles in React Native (my favorite feature of these developer tools!). The new version comes with this feature that also works with inspector in the developer menu. Previously, it was a problem to write styles and have to wait for the app to reload to see the changes. Now we can debug and implement style properties and see the effect of the change instantly without reloading the app.

You can learn more about using React’s Developer Tools app here.

5. React Native Debugger

If you’re using Redux in your React Native app, React Native Debugger is probably the right debugger for you. It’s a standalone desktop app that works on macOS, Windows, and Linux. It integrates both Redux’s DevTools and React’s Developer Tools in one app so you don’t have to work with two separate apps for debugging.

React Native Debugger is my favorite debugger and the one I usually use in my work with React Native. It has an interface for Redux’s DevTools where you can see the Redux logs and the actions, and an interface for React’s Developer Tools where you can inspect and debug React elements. You can find the installation instructions here. You can connect with this debugger in the same way you open Chrome’s inspector.

Using React Native Debugger over Chrome’s DevTools has some advantages. For example, you can toggle the inspector from the Dev Menu to inspect React Native elements and edit styles, which isn’t available in Chrome’s DevTools.

6. React Native CLI

You can use the React Native CLI to do some debugging as well. You can use it for showing the logs of the app. Hitting react-native log-android will show you the logs of db logcat on Android, and to view the logs in iOS you can run react-native log-ios, and with console.log you can dispatch logs to the terminal:

console.log("some error🛑")

You should then see the logs in the terminal.

You can use the React Native CLI to get some relevant info about the libraries and the dependencies you’re using in your app, by running react-native info on the terminal. It shows us some useful info about the tools you’re using. For instance, here’s an example of an output when you run react-native info:

You can use this info to fix some bugs caused by version mismatches of a tool you’re using in your project, so it’s always good to check the environment info using this command.

Summary

There are lots of tools for debugging React Native in addition to the ones we’ve looked at here. It really depends on the specific needs of your project. I mostly use React Native Debugger Desktop because I often work with Redux, and it combines an array of tools in one app which is great and a time saving.