Setting Up your React Native Navigation

Use Redux for routing at your own peril

There are already scores of articles and blogs in relation to this topic, and this also doesn't claim any superiority to its contemporaries, nor assumes any ability to put the final nail on the subject.

I've recently built a relatively large React native application , and by virtue of its size, it involved quite a number of screens that a user can go back and forth. With also the UI requirements in the back drop, I had to be careful on how I structure my routing/navigation structure.

The first UI requirement was to not use the default headerMode provided by default on react native navigation. I was suppose to create a custom one(nicer one). The obvious inconvenience of this is that I have to keep track of the current screen and the previous screen.

The other UI requirement was to change the status bar color to some certain screens. You can easily do this if you going to set the status bar color to every screen, but when building big application, you want to do this dynamically in one place, remember ;we don't want to violate Tech Prophets Mantra - DRY.

The first thing one had to do is set a layout that we can wrap up our navigation stack

  <SafeAreaLayout>
        <NavigationContainer
          ref={navigationRef}
          independent={true}
        >
          <Stack.Navigator initialRouteName={'Login'}>
            {stackData.map((item, index) => (
              <Stack.Screen
                key={index}
                name={item.name}
                options={{
                  headerMode: 'none',
                }}
                component={item.component}
              />
            ))}
          </Stack.Navigator>
        </NavigationContainer>
    </SafeAreaLayout>

In my Layout wrapper component, I needed to have access to the current and previous screen, so I can be able to do my routing globally. Thus a first step is to create a ref of the navigation container , and then store the current route on the local state. Now we going to set our state on the onStateChange function of the navigation container and then pass the values through our Layout component

  const navigationRef = useRef()
  const [activeScreen, setActiveScreen] = useState('')
  const [prevScreen, setPrevScreen] = useState('')

 <SafeAreaLayout activeScreen={activeScreen}  prevScreen={prevScreen}
   navigation={navigationRef.current}>
    <NavigationContainer
          ref={navigationRef}
          onReady={() => {
            routeNameRef.current = navigationRef.current.getCurrentRoute().name
            setActiveScreen(navigationRef.current.getCurrentRoute().name)
          }}
          onStateChange={async () => {
            const previousRouteName = routeNameRef.current
            const currentRouteName = navigationRef.current.getCurrentRoute().name

            setPrevScreen(previousRouteName)
            setActiveScreen(currentRouteName)
            routeNameRef.current = currentRouteName
          }}
          independent={true}
        >
 .........

Our Layout Component is very simple, it get the props, and pass the children it should render. In my HeaderTab Component, I just use the navigation to route.

export default function SafeAreaLayout(props) {

  const { activeScreen, prevScreen, navigation, children } = props

  return  (

      <SafeView activeScreen={activeScreen}  />
     <HeaderTab prev={prevScreen} navigation={navigation} text={activeScreen} />
        <StatusBar style={'auto'}></StatusBar>
        {props.children}
       <HeaderTab/>
      </SafeView>

  ) 

}

Now, as much as this layout is simple, it helped me a lot with regards to styling some screens uniquely and more importantly , to avoid the use of Redux to keep track of my screens. Initially, I Implemented Redux for this purpose , which proved to slow down the screen transition badly, specifically on Android, you had to wait a few seconds for routing to happen. One might argue that I didn't implement Redux properly, which is like saying 'heads you win, tails I lose'. Any library that requires developers to go to the advance section of the documentation to implement it properly should be reserved for scholars not developers that build software for clients, with very limited deadlines.