Search code examples
react-nativereact-native-flatlist

How to use ScrollToIndex in React Native?


I use a FlatList to display search results.

    <View>
      <FlatList
        data={this.state.films}
        keyExtractor={(item) => item.id.toString()}
        renderItem={({item}) => <FilmItem film={item}/>}
      />
    </View>

However, when the user starts a second search, this list does not restart to index 0. So I would like to add ScrollToIndex or viewPosition. I tried this but it doesn't work :

   <View>
      <FlatList
        data={this.state.films}
        keyExtractor={(item) => item.id.toString()}
        renderItem={({item}) => <FilmItem film={item}/>}
        scrollToItem={(index) => {0}}
      />
    </View>

Could you please explain me why this is wrong and what would be the best solution ?

Thanks a lot,


Solution

  • Try this... I made a bunch of changes and have put comments:

    // Components/Search.js
    
    import React from "react";
    import {StyleSheet, View, TextInput, Button, Text, FlatList, ActivityIndicator} from "react-native";
    import FilmItem from "./filmItem";
    import {getFilmsFromApiWithSearchedText} from "../API/TMDBApi";
    
    class Search extends React.Component {
      flatListRef = null; // declaring this here to make it explicit that we have this available
    
      constructor(props) {
        super(props);
        this.searchedText = "";
        this.state = {
          films: [],
          isLoading: false,
        };
      }
    
      _loadFilms = () => {
        // needs to be an arrow function so `this` is bound to this component
    
        this.scrollToIndex(); // assumed you meant to actually call this?
    
        if (this.searchedText.length > 0) {
          this.setState({isLoading: true});
          getFilmsFromApiWithSearchedText(this.searchedText).then(data => {
            this.setState({
              films: data.results,
              isLoading: false,
            });
          });
        }
      };
    
      // needs arrow to use `this`
      _searchTextInputChanged = text => {
        this.searchedText = text;
      };
    
      // needs arrow to use `this`
      _displayLoading = () => {
        // better to return null if not loading, otherwise return loading indicator
        if (!this.state.isLoading) return null;
    
        return (
          <View style={styles.loading_container}>
            <ActivityIndicator size='large' />
          </View>
        );
      };
    
      scrollToIndex = () => {
        // you previously had this inside another method
        this.flatListRef && this.flatListRef.scrollToIndex({index: 1}); // checking it exists first
      };
    
      render() {
        return (
          <View style={styles.main_container}>
            <TextInput
              style={styles.textinput}
              placeholder='Titre du film'
              onChangeText={text => this._searchTextInputChanged(text)}
              onSubmitEditing={this._loadFilms} // no need to create a new anonymous function here
            />
    
            <Button title='Rechercher' onPress={this._loadFilms} />
    
            <View>
              <FlatList
                data={this.state.films}
                ref={ref => (this.flatListRef = ref)}
                keyExtractor={item => item.id.toString()}
                onEndReachedThreshold={1} // corrected typo
                onEndReached={() => {
                  console.log("TOC");
                }}
                renderItem={({item}) => <FilmItem film={item} />}
              />
            </View>
            {this._displayLoading()}
          </View>
        );
      }
    }
    
    const styles = StyleSheet.create({
      main_container: {
        marginTop: 60,
        padding: 15,
        flex: 1,
      },
    
      loading_container: {
        position: "absolute",
        left: 0,
        right: 0,
        top: 100,
        bottom: 0,
        alignItems: "center",
        paddingTop: 50,
        backgroundColor: "white",
      },
    
      textinput: {
        height: 50,
        borderColor: "#999999",
        borderWidth: 1,
        paddingLeft: 5,
      },
    });
    
    export default Search;