Managing navigation can become increasingly complex in large and scalable projects as the application grows in size and intricacy. While powerful and flexible, React Navigation presents unique challenges regarding conditional rendering within navigation flows. In this article, I will explore some troubleshooting scenarios faced during my latest project.

Conditional rendering

Navigation requirements can be based on factors such as user roles, permissions, and application state. As the project grows, the navigation logic can become more elaborate, with multiple nested navigation stacks, conditional routes, and dynamic authentication flows. Managing these factors while ensuring a smooth and intuitive user experience can become challenging.

In React Navigation, conditional rendering can be achieved through various techniques: dynamic route configuration, conditional navigation actions, or protected routes. Today, I will focus on the last technique (protected routes and defining different screens based on some conditions in our authentication flow) and a challenge my team and I faced in the recent project.

Challenges of conditional rendering

Protected routes were implemented by rendering screens conditionally within navigation stacks based on the user authentication state.

To navigate from one initial route to the other, we just had to set the new authentication state.NewCustomerNavigator and NewDeviceNavigator stack navigators:

In that case, we wanted to change our authentication state in the UserFlow component and be redirected to the Home page when the back button was pressed:

The back button handler, which navigated users from NewCustomerNavigator to NewDeviceNavigator in the UserFlow screen, worked as it should because both screens (UserFlow and Home) existed in different stack navigators.

Conditional rendering in navigation offers flexibility and customization. It also presents several challenges and can lead to complex navigation logic, making it challenging to maintain and debug, especially as the project grows. One of the challenges we faced was that there were screens where we needed to navigate to a new authentication flow.

Let’s discover such cases in the following views: CurrentAccount and ExitPath.

ExitPath screen was designed to display relevant business error information to users and potentially offer options for resolving the issue or retrying the action that caused an error. Its dynamic back button functionality allowed users to navigate back to various screens based on the business error type.Below, you can see a REDIRECT_TO_PHONE_NUMBER case, which allowed us to change the stack navigator by setting the authentication state:

CurrentAccount had the functionality to navigate to a specific screen on the initial render.

CurrentAccount, ExitPath and VerifyPhoneNumber stack navigators:

When we were in the CurrentAccount or ExitPath, we wanted to navigate to the VerifyPhoneNumber screen by changing the authentication state with a custom hook useAuth(). Unfortunately, we still stayed on the same screen. We simply received the below error:

The action 'NAVIGATE' with payload {"name":"verify-phone-number-screen"} 
was not handled by any navigator.

Do you have a screen named 'verify-phone-number-screen'?

If you're trying to navigate to a screen in a nested navigator, see 
https://reactnavigation.org/docs/nesting-navigators#navigating-to-a-screen-in-a-nested-navigator.

We encountered a fair share of challenges regarding conditional rendering in such cases. Seamless integration of conditional rendering was more complex than anticipated.

Finally, we concluded that this was simply caused by the fact that we did not wait for the navigator to be replaced before navigating to the specific screen. We were required to apply two actions without auto-batching.

In that case, we created the batchSplitter function to split up batching:

Then we used batchSplitter in the following way:

(ExitPath)

(CurrentAccount)

Batching was particularly useful when we had multiple state updates or side effects that needed to occur due to some event, such as user interactions or data fetching. But in our specific case, we required two separate actions, and to achieve this, we implemented a promise to avoid batching for swapping stacks.

Conclusion

React Navigation in scalable and large projects requires a strategic approach to conditional rendering and navigation management. By leveraging techniques such as dynamic route configuration and protected routes, we can create more intuitive and flexible navigation experiences while mitigating the challenges of managing complexity in navigation flows, which can behave differently depending on specific scenarios.