Day 6 - July 5, 2022

Topics Covered

  • Navigating between screens
  • Passing data between screens
  • Customizing navigation header bars
  • Tab and drawer navigators
  • Handling state

Navigating between screens

Most apps will have some sort of navigation requirements. In React Native, we can accomplish this using the react-navigation package. Let's start off with an example.

Code Example
Output
Rendered output

In previous code examples, we typically return a function to render JSX to the screen. In the above example, we are not returning JSX in the way we are used to. Instead we call the createStackNavigator() function from the createAppContainer() function.

The first argument of the createStackNavigator() function determines what screens will be handled by the navigator. Each screen is simply a React component and is specified as a mapping in a plain JavaScript object: { Home, Settings }.

The second argument includes options to fine-tune the navigator. In the code example, we set the default route (or screen) to be displayed after the application is started.

Take a look at the Home and Settings functions. As mentioned earlier, these are React components. In fact, they are Functional React components. Eact component receives a navigation argument. This argument is passed to your screen by react-navigation and contains all of the routing functionality you need. We use the navigate() function to transition to different screens. The navigator component handles the transition on our behalf, so we don't need to worry about hiding or showing components.

Copy the code and run the code example. When the program is started the Home component is displayed. Clicking on the Go to Settings button will navigate to the Settings component. After navigation, the Home component is hidden, the Settings component is displayed, and the title is updated to reflect the new screen. There are two ways to return to the Home page. The user can click on the Go Back Home button or use the navigation bar. It contains a Back arrow button that will return the user to the previous screen. If you run the application on Android, you can also use the standard back button found outside of the app.

Passing data between screens

We learned that the react-navigation package offers an easy way to transition between screens in our application. In the last code example, each screen is independent of the previous screen. In other words, we are not passing data between the screens. Think of a shopping cart application. A common feature (requirement?) is to allow the user to choose an item and view details about that item before they buy it.

react-navigation makes it easy to pass data between components. When calling navigate(), simply pass a JavaScript object as the second argument. A component can use the getParam() function to receive key/value pairs from that object. Let's look at another example. Pay attention to lines 10-12 where you see navigate("Details", { title: "First Item" }), here we are passing information to the Details component. On line 20, the value is received and displayed by the Details component.

Code Example
Output
Rendered output

Customizing navigation header bars

The navigation bars you've seen so far are pretty basic - they contain the route name and a back button. Let's make the navigation header for the details page more intuitive.

Code Example
Output
Rendered output
Rendered output

The first thing you will notice is that we are now passing more data to the Details component. Since we are using functional components, we can customize the navigation header by setting navigation options as shown on lines 37-44. Instead of showing the route name, the navigation header now shows the item title. Additionally, a button is added to the nav bar to allow users to purchase the item. The button won't do too much since the onPress event hasn't been handled but it does transition into the disabled state if there is insufficient quantity remaining: disabled={navigation.getParam("qtyAvail") === 0}.

Tab and drawer navigators

So far, we used stack navigator and Button components to link to other screens. Instead, you may prefer to use a bottom tab navigator or a drawer navigator.

In the next code example, we are using Platform.select() to determine what OS our application is running on then we are rendering the appropriate navigator. If the app is running on iOS, we use a bottom tab navigator, on Android, a drawer navigator, or on any other device, a stack navigator. So, depending on what OS the app is run on, the navigation will appear differently.

It is worth noting that you aren't lmited to using tab navigation on iOS and drawer navigation on Android. Each navigator can be used on any device. This was however a great way to remind you of the Platform.select() function.

Code Example

Handling state

We have already learned how to work with state. As a reminder, state is data that is passed down to components so that the components can render or change this data. But how do we work with state at the same time as navigators.

Code Example

In the following example, we will make modifications to the application introduced in the topic Customizing navigation header bars. Start off by looking at the App() function. This is a functional component and therefore we are calling useState to set up default state values. We then define a function called decrementItem(). This function will decrease the quantity available for a single key in the state object. Finally, we return the navigator component but first we pass a property called screenProps. screenProps will allow the components contained in the navigator to access the state data.

Looking at the ItemList component, a change was made in the function declaration to include the items screen property passed into the navigator. It is used during in the JSX to render the navigator buttons. It probably would have made more sense to render each <Button> dynamically using the keys contained in the items object, but instead they were hard-coded.

Finally, in the Details component, navigationOptions have been set up in a way that allows the Buy button to update state. When the button is pressed, the decrementItem() function is called thus reducing the quantity available. Upon clicking the button, you will see the UI will automatically refresh to show the new state / quantity. When the available quantity reaches zero, the button will disable, preventing additional clicks.