Search code examples
react-nativereact-navigationreact-native-iosreact-navigation-stack

Snapchat-like Horizontal ScrollView Combined with React Navigation


I'm trying to create a ScrollView similar to Snapchat's frontend, with 3 screens. However, I want to be able to use react-navigation's ability to set an initial route so that every time the home screen loads, it starts on the middle screen instead of the left-most screen.

This is for react-native version: 0.57.1, and react-navigation version: 3.0.9. This works fine when I put all 3 screens in the ScrollView component directly, but then I can't find a way to select which screen is displayed initially.

Here is something similar to what I'm aiming for:

const HomeScreenStack = createStackNavigator({
    Goals: GoalsScreen,
    Dash: DashScreen,
    Plans: PlansScreen,
}, {
    initialRouteName: "Dash"
})

class HomeScreen extends React.Component {
    render() {
        return (
            <ScrollView
                horizontal={true}
                pagingEnabled={true}
                showsHorizontalScrollIndicator={false}
                showsVerticalScrollIndicator={true}>
                <HomeScreenStack />
            </ScrollView>
        )
    }
}

I expect HomeScreenStack to display all 3 routes within a ScrollView, but I get an error saying:

Invariant Violation: Invariant Violation:
The navigation prop is missing for this navigator.
In react-navigation 3 you must set up your app container directly.
More info: https://reactnavigation.org/docs/en/app-containers.html

Solution

  • Rather than using a ScrollView, you could take advantage of react-navigation's createMaterialTopTabNavigator and nullify the tabBarComponent. It has swipe navigation enabled by default.

    You also need to set up an app container for react-navigation, which is where that error is coming from. Note that AppContainer should be used only once and in the main entry point file, such as App.js.

    import { createAppContainer, createMaterialTopTabNavigator } from 'react-navigation'
    
    const HomeNavigator = createMaterialTopTabNavigator(
      {
        Goals: GoalsScreen,
        Dash: DashScreen,
        Plans: PlansScreen,
      },
      {
        initialRouteName: "Dash",
        tabBarComponent: null
      }
    )
    
    const AppContainer = createAppContainer(HomeNavigator)
    
    class HomeScreen extends React.Component {
      render() {
        return (
          <AppContainer />
        )
      }
    }