Search code examples
react-nativereact-navigationreact-native-scrollview

React Native - how to scroll a ScrollView to a given location after navigation from another screen


Is it possible to tell a ScrollView to scroll to a specific position when we just navigated to the current screen via StackNavigator?

I have two screens; Menu and Items. The Menu is a list of Buttons, one for each item. The Items screen contain a Carousel built using ScrollView with the picture and detailed description of each Item.

When I click on a button in the Menu screen, I want to navigate to the Items screen, and automatically scroll to the Item that the button represent.

I read that you can pass in parameters when using the StackNavigator like so: but I don't know how to read out that parameter in my Items screen.

navigate('Items', { id: '1' })

So is this something that is possible in React Native and how do I do it? Or perhaps I'm using the wrong navigator?

Here's a dumbed down version of my two screens:

App.js:

const SimpleApp = StackNavigator({
    Menu: { screen: MenuScreen},
    Items: { screen: ItemScreen }
  }
);

export default class App extends React.Component {
  render() {
    return <SimpleApp />;
  }
}

Menu.js

export default class Menu extends React.Component {
    constructor(props){
        super(props)
        this.seeDetail = this.seeDetail.bind(this)
    }

    seeDetail(){
        const { navigate } = this.props.navigation;
        navigate('Items')
    }

    render(){
        <Button onPress={this.seeDetail} title='1'/>
        <Button onPress={this.seeDetail} title='2'/>
    }
}

Items.js

export default class Items extends React.Component {
  render(){
    let scrollItems = [] //Somecode that generates and array of items
    return (
      <View>
        <View style={styles.scrollViewContainer}>
          <ScrollView 
          horizontal
          pagingEnabled
          ref={(ref) => this.myScroll = ref}>
            {scrollItems}
          </ScrollView>
        </View>
      </View>
    )
  }  
}

P.S I am specifically targeting Android at the moment, but ideally there could be a cross-platform solution.


Solution

  • I read that you can pass in parameters when using the StackNavigator like so: but I don't know how to read out that parameter in my Items screen.

    That is achieved by accessing this.props.navigation.state.params inside your child component.

    I think the best time to call scrollTo on your scrollview reference is when it first gets assigned. You're already giving it a reference and running a callback function - I would just tweak it so that it also calls scrollTo at the same time:

    export default class Items extends React.Component {
      render(){
        let scrollItems = [] //Somecode that generates and array of items
        const {id} = this.props.navigation.state.params;
    
        return (
          <View>
            <View style={styles.scrollViewContainer}>
              <ScrollView 
              horizontal
              pagingEnabled
              ref={(ref) => {
                this.myScroll = ref
                this.myScroll.scrollTo() // !!
              }>
                {scrollItems}
              </ScrollView>
            </View>
          </View>
        )
      }  
    }
    

    And this is why I use FlatLists or SectionLists (which inherit from VirtualizedList) instead of ScrollViews. VirtualizedList has a scrollToIndex function which is much more intuitive. ScrollView's scrollTo expects x and y parameters meaning that you would have to calculate the exact spot to scroll to - multiplying width of each scroll item by the index of the item you're scrolling to. And if there is padding involved for each item it becomes more of a pain.