From 4dcc1d3efbd86a4ac42c801af3303e4dae4c0418 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Wed, 7 Feb 2024 20:44:34 -0800 Subject: [PATCH] Fix onStartReached not called when list content is small (#42902) Summary: Currently if the virtualized list content is small `onStartReached` won't be called initially when the list is mounted. This is because when the content is small `onEndReached` will be called initially preventing `onStartReached` from being called. In `_maybeCallOnEdgeReached` calling `onEndReached` and `onStartReached` are in the same conditional so they cannot both be triggered at once. To improve the consistency of `onStartReached` we should call both `onEndReached` and `onStartReached` if needed. ## Changelog: [GENERAL] [FIXED] - Call onStartReached initially when list is small and `onEndReached` is called Pull Request resolved: https://github.com/facebook/react-native/pull/42902 Test Plan: I used this code to test in RN Tester (replace content of RNTesterAppShared.js) ```ts import React, { useState, useEffect } from "react"; import { StyleSheet, FlatList, View, Text, TouchableOpacity } from "react-native"; function App() { const [data, setData] = useState(generatePosts(4)); const [idCount, setIdCount] = useState(1); const renderItem = ({ item }) => ; const keyExtractor = (item) => item.id.toString(); console.log("-------") return ( console.log("onEndReached")} onStartReachedThreshold={0.05} onStartReached={() => console.log("onStartReached")} inverted /> { setIdCount(state => state + 1) setData(generatePosts(2)) }}> Press ); } function Item({ data }) { return ( {data.id} - {data.title} ); } const styles = StyleSheet.create({ item: { backgroundColor: "#f9c2ff", padding: 20, marginVertical: 8, marginHorizontal: 16, }, title: { fontSize: 24, }, }); const generatePosts = (count, start = 0) => { return Array.from({ length: count }, (_, i) => ({ title: `Title ${start + i + 1}`, vote: 10, id: start + i, })); }; export default App; ``` Before the change only onEndReached is called, after the change both onStartReached and onEndReached is called. Reviewed By: sammy-SC Differential Revision: D53518434 Pulled By: cipolleschi fbshipit-source-id: bc34e0d4758df6d5833be7290e5a66efaf252ffd --- .../virtualized-lists/Lists/VirtualizedList.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/virtualized-lists/Lists/VirtualizedList.js b/packages/virtualized-lists/Lists/VirtualizedList.js index 8638f5f80f812e..9f950916a2dfc0 100644 --- a/packages/virtualized-lists/Lists/VirtualizedList.js +++ b/packages/virtualized-lists/Lists/VirtualizedList.js @@ -1548,7 +1548,7 @@ class VirtualizedList extends StateSafePureComponent { // Next check if the user just scrolled within the start threshold // and call onStartReached only once for a given content length, // and only if onEndReached is not being executed - else if ( + if ( onStartReached != null && this.state.cellsAroundViewport.first === 0 && isWithinStartThreshold && @@ -1560,13 +1560,11 @@ class VirtualizedList extends StateSafePureComponent { // If the user scrolls away from the start or end and back again, // cause onStartReached or onEndReached to be triggered again - else { - this._sentStartForContentLength = isWithinStartThreshold - ? this._sentStartForContentLength - : 0; - this._sentEndForContentLength = isWithinEndThreshold - ? this._sentEndForContentLength - : 0; + if (!isWithinStartThreshold) { + this._sentStartForContentLength = 0; + } + if (!isWithinEndThreshold) { + this._sentEndForContentLength = 0; } }