Navigation Patterns in React Native

The Navigation router for React Native provides 100% native navigation on iOS and Android. In my first post I introduced the Virtual Stack. The Virtual Stack is a JavaScript array representation of the Native Stack of screens. The Navigation router syncs the changes you make to the Virtual Stack onto the Native Stack. Being able to interrogate the Stack in JavaScript sets the Navigation router apart from React Native Navigation, the only other fully native navigator. In this post I’ll use the Virtual Stack to implement two navigation patterns that present a challenge for React Native Navigation.

Pop to a Screen

Anybody that’s used the Twitter App knows that the Stack of screens can soon get unwieldy. Open Tweet A, read a reply to a reply then open Tweet A again and select a different reply. You end up with a Stack that’s 5 Tweets deep.

Home → Tweet A → Tweet B → Tweet C → Tweet A → Tweet D

One way you can address this is by preventing the same Tweet appearing in the Stack twice. The first time you open Tweet A you push it, but the second time you pop back to it instead. That way the example Stack ends up only 2 Tweets deep.

Home → Tweet A → Tweet D

The Virtual Stack is available in JavaScript as an array of crumbs. You can identify the screen that each crumb represents using its state and data properties. Loop through the crumbs looking for Tweet A. If you don’t find it then add Tweet A to the Virtual Stack by navigating to it. If you do find it then remove all the items up to Tweet A by calling navigateBack, passing in the number of crumbs to remove.

const { crumbs } = stateNavigator.stateContext;
const tweetIndex = crumbs.findIndex(({ state, data }) => (
state.key === 'Tweet' && data.id === 'A'
));
if (tweetIndex === -1) {
stateNavigator.navigate('Tweet', { id: 'A' });
} else {
stateNavigator.navigateBack(crumbs.length — tweetIndex);
}

Push Multiple Screens

Twitter notifies you when any one of your Tweets receives replies. If there’s only a few replies, instead of taking you to the notifications tab, the notification could open up all the replies at once. Then you could read them one by one as you navigate back. If you received Tweets A and B in reply, for example, then the notification would push both these Tweets onto the Stack.

Home → Tweet A → Tweet B

The inefficient way to do this is with successive navigate calls. This would render both Tweet screens at once when you only need to render Tweet B to begin with. Tweet A shouldn’t render until you navigate back to it.

The efficient way is to add Tweets A and B to the Virtual Stack in one go rather than one at a time. Then the native code receives these two additions as a single change and can optimise the corresponding push onto the Native Stack so that only Tweet B renders at first.

You use fluent navigation to add multiple items to the Virtual Stack. Fluent navigation allows you to build a list of navigation instructions. You give these instructions to the navigateLink function which applies them all to the Virtual Stack in a single hit.

const url = stateNavigator.fluent(true)
.navigate('Tweet', { id: 'A' })
.navigate('Tweet', { id: 'B' })
.url;
stateNavigator.navigateLink(url);