Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix sporadic issue with onEndReached called on load when not needed
Summary: Fixes #16067 The issue is due to a race between `onLayout` and `onContentSizeChange`, which in general should be fine because there is no expectation of ordering between the two, and only causes issues with certain configurations. The bug can be triggered if `initialNumToRender` is smaller than needed to fill past the `onEndReachedThreshold` (say the default, 10, is only 580px tall, but it takes 15 to reach the threshold). This will cause an incrementally render of more items to try and fill the viewport. The problem is that if the `onLayout` comes back before the first `onContentSizeChange`, it will first do the state increment to render 20 items and then the stale `onContentSizeChange` callback from 10 items will fire and we'll think that the content size for 20 items is 580px when in fact it's 1160px (which is past the threshold). If those 20 items are also all of our available data, then we'll call `onEndReached` because we think we've rendered everything and are still within the `onEndReachedThreshold`. The fundamental problem here is the system getting confused when a stale async `onContentSizeChange` comes in after increasing `state.last`. I wish there was a concrete timeframe, but Fabric will give us more flexibility to do things synchronously so hopefully we can avoid class of issues once that roles out. The fix here simply adds a check to make sure `contentLength` has been set before adjusting the render window so it's not possible to increase the window size before the initial `onContentSizeChange` callback fires. For completeness, there are a few user-code workarounds to avoid this issue entirely: 1) Provide the `getItemLayout` prop so the list doesn't have to rely on async layout data (you should do this whenever possible anyway for better perf). e.g. for the original snack example, you can just add `getItemLayout={(d, index) => ({length: 58, offset: 58 * index, index})}` since all the rows are height 58 and the issue will no longer repro. Note this is fragile and must be kept in sync with UI changes, a11y font scaling, etc - a more robust approach could be to render a single representative row offscreen and measure it with `onLayout` then use that value. 2) If `getItemLayout` is not feasible to compute for your UI, increase `initialNumToRender` to cover the `onEndReachedThreshold`. 3) And/or add your own logic to protect against extra calls to `onEndReached` as others have suggested. Changelog: [General][Fixed] - Fix sporadic issue with onEndReached called on load when not needed # Test Plan Adds a new jest test that fails without this fix and succeeds with it. Reviewed By: TheSavior Differential Revision: D18966721 fbshipit-source-id: de05d9f072e24a2faf351e7f5d60578a31def996
- Loading branch information