Search code examples
react-nativerefactoringreact-navigationecmascript-2016

Is it possible to refactor React-Navigator Elements?


I'm learning the ropes with React Native and React Navigator at the moment and I've come across something in development where I feel like I want to implement the DRY (don't repeat yourself) technique.

Here's my component code:

export default class App extends React.Component {
  render() {
    const MainNavigator = TabNavigator({
      welcome: { screen: WelcomeScreen },
      auth: { screen: AuthScreen },
      main: { 
        screen: TabNavigator({
          map: { screen: MapScreen },
          deck: { screen: DeckScreen },
          review: {
            screen: StackNavigator({
              review: { screen: ReviewScreen },
              settings: { screen: SettingsScreen }
            })
          }
        }, { 
          tabBarPosition: 'bottom',
          lazyLoad: true,
          animationEnabled: false,
          swipeEnabled: false
        })
      }
    }, {
      tabBarPosition: 'bottom',
      lazyLoad: true,
      animationEnabled: false,
      swipeEnabled: false  
    });

    return <MainNavigator />;
  }
}

As you can see, I have the following chunk of repeatable code:

tabBarPosition: 'bottom',
lazyLoad: true,
animationEnabled: false,
swipeEnabled: false

I tried to refactor the same way that you would do styles in React components like this:

export default class App extends React.Component {
  render() {
    const MainNavigator = TabNavigator({
      welcome: { screen: WelcomeScreen },
      auth: { screen: AuthScreen },
      main: { 
        screen: TabNavigator({
          map: { screen: MapScreen },
          deck: { screen: DeckScreen },
          review: {
            screen: StackNavigator({
              review: { screen: ReviewScreen },
              settings: { screen: SettingsScreen }
            })
          }
        }, { defaultTabStyles })
      }
    }, { defaultTabStyles });

    return <MainNavigator />;
  }
}

const defaultTabStyles = {
  tabBarPosition: 'bottom',
  lazyLoad: true,
  animationEnabled: false,
  swipeEnabled: false
};

As you can see, this is a much cleaner way of doing things if it would work. But it doesn't work, so is there a way of refactoring this correctly or do I need to stick with my original implementation?


Solution

  • It looks like you are wrapping your defaultTabStyles object in curly braces, which thanks to the ES6 object property shorthand creates the following object:

    {
      defaultTabStyles:
        {
          animationEnabled: false,
          lazeLoad: true,
          swipeEnabled: false,
          tabBarPosition: 'bottom',
        },
    }
    

    Which contains none of the keys the navigator is looking for. Try removing the curly braces:

    export default class App extends React.Component {
      render() {
        const MainNavigator = TabNavigator({
          welcome: { screen: WelcomeScreen },
          auth: { screen: AuthScreen },
          main: { 
            screen: TabNavigator({
              map: { screen: MapScreen },
              deck: { screen: DeckScreen },
              review: {
                screen: StackNavigator({
                  review: { screen: ReviewScreen },
                  settings: { screen: SettingsScreen }
                })
              }
            }, defaultTabStyles) // instead of { defaultTabStyles }
          }
        }, defaultTabStyles);  // instead of { defaultTabStyles }
    
        return <MainNavigator />;
      }
    }
    
    const defaultTabStyles = {
      tabBarPosition: 'bottom',
      lazyLoad: true,
      animationEnabled: false,
      swipeEnabled: false
    };
    

    Furthermore, to keep it DRY further down the road, you can override default options for specific navigators using spread syntax:

    const mainScreenTabStyles = {
      ...defaultTabStyles,
      tabBarPosition: 'top',
    }