Home > Mobile >  Why I am not able to use scrollToIndex method of FlatList in react native?
Why I am not able to use scrollToIndex method of FlatList in react native?

Time:10-22

I have a list of users, which I render within FlatList. Initially, I render 10 users, then when I scroll to the bottom on the page, I render 10 more and so on. When I don't have any more users to load, I display a button at the bottom on the page saying "No more users".

Just for the sake of testing - I wanted to navigate to the 2nd user when pressing this button. I am calling the function, yet, when I press the button I am not navigated to the second - there are no changes at all.

Here is my code:

const UsersScreen = (props) => {
  const flatListRef = useRef(null);
  const limit = 10;
  const [users, setUsers] = useState([]);
  const [noMore, setNoMore] = useState(false);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    (async () => {
      let initialUsers = await fetchInitialUsers();
      setUsers(initialUsers);
      setLoading(false);
    })();
  }, []);

  const fetchNextBatch = async () => {
    let moreUsers;
    try {
      moreUsers = await fetchMoreUsers();
      if (moreUsers.length == 0) {
        setNoMore(true);
      } else {
        setUsers([...users, ...moreUsers]);
      }
    } catch (error) {
      console.log(error);
    }
  };

  const isCloseToBottom = ({
    layoutMeasurement,
    contentOffset,
    contentSize,
  }) => {
    const paddingToBottom = 30;
    return (
      layoutMeasurement.height   contentOffset.y >=
      contentSize.height - paddingToBottom
    );
  };

  function onLayoutFunction() {
    // here I see "function on layout was called:  [Function scrollToIndex]" on the terminal
    console.log(
      "function on layout was called: ",
      flatListRef.current.scrollToIndex
    );
    //scroll to random element, just to see if scrollToIndex works
    flatListRef.current.scrollToIndex({
      index: 5,
      viewPosition: 0,
      viewOffset: 30,
    });
  }

  return (
    <View style={styles.container}>
      {loading ? (
        <ActivityIndicator />
      ) : (
        <ScrollView
          onScroll={({ nativeEvent }) => {
            if (isCloseToBottom(nativeEvent)) {
              fetchNextBatch();
            }
          }}
          scrollEventThrottle={400}
        >
          <FlatList
            numColumns={1}
            horizontal={false}
            data={users}
            onLayout={() => onLayoutFunction()}
            //do I need this?
            getItemLayout={(data, index) => {
              return { length: 120, index, offset: 120 * index };
            }}
            keyExtractor={(item) => item.id}
            ref={(ref) => (flatListRef.current = ref)}
            renderItem={({ item }) => <User user={item} />}
          />
        </ScrollView>
      )}
      {noMore ? (
        <TouchableOpacity onPress={onLayoutFunction}>
          <Text style={{ fontSize: 15 }}>No more users</Text>
        </TouchableOpacity>
      ) : null}
    </View>
  );
};

I've read too many posts regarding this topic, and still I don't see what I am doing wrong? Why I can not navigate to the index I want?

My UsersScreen component is within stack navigator if that makes any difference?

CodePudding user response:

I think the problem is that the FlatList is nested inside a ScrollView. I tried removing the ScrollView and the ScrollToIndex function works.

<View style={styles.container}>
  {loading ? (
    <ActivityIndicator />
  ) : (
      <FlatList
        onScroll={({ nativeEvent }) => {
          if (isCloseToBottom(nativeEvent)) {
            fetchNextBatch();
          }
        }}
        scrollEventThrottle={400}
        numColumns={1}
        horizontal={false}
        data={users}
        onLayout={() => onLayoutFunction()}
        //do I need this?
        getItemLayout={(data, index) => {
          return { length: 120, index, offset: 120 * index };
        }}
        keyExtractor={(item) => item.id}
        ref={(ref) => (flatListRef.current = ref)}
        renderItem={({ item }) => <User user={item} />}
      />
  )}
  {noMore ? (
    <TouchableOpacity onPress={onLayoutFunction}>
      <Text style={{ fontSize: 15 }}>No more users</Text>
    </TouchableOpacity>
  ) : null}
</View>
  • Related