Fix artificial scroll limit expanding on scroll to un-measured area (2nd of 4 problems that cause #1254) #2413
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
I found 4 problems that cause the Inverted VirtualizedList to go wild (#1254). This PR will explain and fix the 2nd of 4 problems found.
If we fix the following 4 problems, issue #1254 will be fixed and FlatList’s scroll will be more stable:
Update:
PR 2, 3, and 4 will fix 'Flatlist with expensive items breaks scroll' issue. PR 1 is enough to fix the Inverted Flatlist issue if your Flatlist's items are cheap to mount.
$lead_spacer expands scroll artificially when Inverted VirtualizedList is mounting new items —> Problem Explanation and Solution below.
VirtualizedList skip items for offset measuring when the user scrolls very fast while new items are mounted and measured (this happens also for normal lists) —> Problem Explanation and Solution in this PR.
VirtualizedList gets offsets equal to zero for items that are not the list's first item (this happens also for normal lists) —> Problem Explanation and Solution in this PR.
Video of Inverted FlatList with all problems fixed:
2022-10-23.17-49-22.mp4
2nd Problem
$lead_spacer expands scroll limit artificially when Inverted VirtualizedList is mounting new items. (2nd of 4 problems that cause #1254)
In a FlatList with items with different heights, the scroll is limited to the last measured item. That’s because
VirtualizedList
(the innerFlatList
's component) must measure the offset of mounted items before it tries to mount new items. In this way, all items in the virtual area are measured and the_frames
object is complete.The scroll limit should be only expanded when the user tries to scroll beyond the scroll limit (unmeasured area) and then new items are mounted and their offsets are measured and saved in
_frames
. When recently mounted items are measured, the scroll limit is expanded to the new latest measured item, then the user will be ready to keep scrolling to unmeasured area and repeat the process to keep expanding the scroll limit until the last item is met.Sometimes users may “overscroll” to unmeasured areas while previously mounted items haven't been measured yet, and
VirtualizedList
starts skipping items for measuring and measures others that shouldn’t be measured yet, leading to a fragmented map of offsets (e.g. we have offset values for …31, 32, 33, then jumps to 37, 38…).Why do users “overscroll”?
Flaltlist constantly mounts and unmounts items. There is a white space mounted on our list called
$tail_spacer
. It helps us to fill with white space the top outside of our virtual area (because it’s an inverted list, for normal lists it fills the bottom), where items were previously mounted and measured but unmounted afterward, so the scroll limit sticks to our latest measured item offset.$tail_spacer
height depends on how much area we had measured, but it reduces to zero when the latest measured item is mounted and the user pretends to scroll to an unmeasured area looking for more items. When$tail_spacer
's height is zero, the scroll is limited and prevents the user from “overscroll”. This gives time to VirtualizedList to properly mount and measure new items to then use their offsets as our new scroll limit.Sometimes
$tail_spacer
has a height greater than zero when it should be zero, allowing the user to “overscroll”.Why sometimes
$tail_spacer
has a height greater than zero when it should be zero?On some updates,
$tail_spacer
gets a negative value for its height, which is an invalid value. Invalid values will be ignored and $tail-spacer’s height will set the valid value of the previous state, instead of setting it to zero.Solution:
The solution is simple. Check
tailSpacerLenght
, if it is below zero then set it to zero:react-native-web/src/vendor/react-native/VirtualizedList/index.js