React is a Virtual UI library. The React core doesn’t touch the DOM. You won’t find any document.createElement statements inside React. Instead, React diffs the component tree across renders and communicates the changes to the React DOM library. It’s React DOM that updates the DOM. That’s where you’ll find calls to document.createElement . That explains why React can work on Native as well as on the Web. The core React engine remains unchanged, but you swap out React DOM for React Native. In place of the DOM calls, React Native creates UI elements using the underlying native APIs on Android and iOS.

The Navigation router for React Native provides 100% native navigation on Android and iOS. The Navigation router is a Virtual Stack library. It does for navigation what React does for UI. The Navigation router core doesn’t contain any Native code. Instead, it diffs the Stack across navigations and communicates the changes to the Navigation React Native library. It’s Navigation React Native that contains the Native code. That’s where you’ll find the Java and Objective-C calls to push and pop scenes. That explains why the Navigation router can work on the Web as well as on Native. The core Navigation engine remains unchanged, but you swap out Navigation React Native for Navigation React Mobile. In place of the Java and Objective-C calls, Navigation React Mobile manages the Stack as an array of DOM elements.

How It All Stacks Up

Let’s look at an example to see how the Virtual Stack works. Say you’re building a Native App that has two scenes. The first scene displays a list of people. Clicking a person takes you through to the second scene that shows their details. The Navigation router represents each scene as a State and the Virtual Stack as an array of States. When the App first loads you navigate to the people State, which adds this State to the Virtual Stack.

[ { state: 'people' } ]

Scenes can also contain data. When you click on a person, you navigate to the person State and pass the selected id. The Navigation router adds the person State to the Virtual Stack along with the id.

[ { state: 'people' }, { state: 'person', data: { id: 12 } } ]

The Navigation router sends the Virtual Stack differences to the Navigation React Native library. This library then reflects the changes onto the actual stack by calling into the underlying Native API. On Android, it starts a new Activity and, on iOS, it pushes a new UIViewController .

In response to an Android back button press, for example, you navigate back to the people State. The Navigation router removes the person State from the Virtual Stack and sends these changes to the client. Navigation React Native then calls finish on the person Activity , which returns you to the list of people.

Just as React’s Virtual UI enables many uses cases, so does the Navigation router’s Virtual Stack. Before navigating to a new State, for example, you can loop through the Stack and navigate back to that State if you find it already exists. Or you can rewrite any item in the Stack by replacing it with a new State and data combination. You can even prime the Stack by navigating through multiple States at once. Navigation React Native is optimised so that only the scene at the top of the Stack renders during a navigation no matter how many changes you make to the Virtual Stack.

Going Native on the Web

You can run a React Native App on the Web by using React Native for Web. It renders Native components as DOM elements, for example, a View renders as a div . But it doesn’t work if you’re using React Native Navigation, until now the only library that offers 100% native navigation. When you call push, React Native Navigation immediately calls into the Native API so there’s no way it can run on the Web. In a similar way that React Native wouldn’t be possible if the React core called into the DOM when rendering a component.