Skip to content

Commit b14daf7

Browse files
committed
🦺 remount FlatList on change to onViewableItemsChanged to protect against crashes on changing numberOfItems or repeatNumbersNTimes on the fly (#42)
1 parent 65192ed commit b14daf7

File tree

1 file changed

+39
-10
lines changed

1 file changed

+39
-10
lines changed

‎src/components/DurationScroll/index.tsx‎

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ const DurationScroll = forwardRef<DurationScrollRef, DurationScrollProps>(
8484
// the number of items in the picker, avoiding regular jumps up/down the list
8585
// whilst avoiding rendering too many items in the picker
8686
if (repeatNumbersNTimesNotExplicitlySet) {
87-
return Math.round(180 / numberOfItems);
87+
return Math.max(Math.round(180 / numberOfItems), 1);
8888
}
8989

9090
return Math.round(repeatNumbersNTimes);
@@ -383,6 +383,10 @@ const DurationScroll = forwardRef<DurationScrollRef, DurationScrollProps>(
383383

384384
const onViewableItemsChanged = useCallback(
385385
({ viewableItems }: { viewableItems: ViewToken[] }) => {
386+
if (numberOfItems === 1) {
387+
return;
388+
}
389+
386390
if (
387391
viewableItems[0]?.index &&
388392
viewableItems[0].index < numberOfItems * 0.5
@@ -405,6 +409,38 @@ const DurationScroll = forwardRef<DurationScrollRef, DurationScrollProps>(
405409
[numberOfItems, safeRepeatNumbersNTimes]
406410
);
407411

412+
const [
413+
viewabilityConfigCallbackPairs,
414+
setViewabilityConfigCallbackPairs,
415+
] = useState<ViewabilityConfigCallbackPairs>([
416+
{
417+
viewabilityConfig: { viewAreaCoveragePercentThreshold: 0 },
418+
onViewableItemsChanged: onViewableItemsChanged,
419+
},
420+
]);
421+
422+
const [flatListRenderKey, setFlatListRenderKey] = useState(0);
423+
424+
const initialRender = useRef(true);
425+
426+
useEffect(() => {
427+
// don't run on first render
428+
if (initialRender.current) {
429+
initialRender.current = false;
430+
return;
431+
}
432+
433+
// if the onViewableItemsChanged callback changes, we need to update viewabilityConfigCallbackPairs
434+
// which requires the FlatList to be remounted, hence the increase of the FlatList key
435+
setFlatListRenderKey((prev) => prev + 1);
436+
setViewabilityConfigCallbackPairs([
437+
{
438+
viewabilityConfig: { viewAreaCoveragePercentThreshold: 0 },
439+
onViewableItemsChanged: onViewableItemsChanged,
440+
},
441+
]);
442+
}, [onViewableItemsChanged]);
443+
408444
const getItemLayout = useCallback(
409445
(_: ArrayLike<string> | null | undefined, index: number) => ({
410446
length: styles.pickerItemContainer.height,
@@ -414,14 +450,6 @@ const DurationScroll = forwardRef<DurationScrollRef, DurationScrollProps>(
414450
[styles.pickerItemContainer.height]
415451
);
416452

417-
const viewabilityConfigCallbackPairs =
418-
useRef<ViewabilityConfigCallbackPairs>([
419-
{
420-
viewabilityConfig: { viewAreaCoveragePercentThreshold: 0 },
421-
onViewableItemsChanged: onViewableItemsChanged,
422-
},
423-
]);
424-
425453
useImperativeHandle(ref, () => ({
426454
reset: (options) => {
427455
flatListRef.current?.scrollToIndex({
@@ -458,6 +486,7 @@ const DurationScroll = forwardRef<DurationScrollRef, DurationScrollProps>(
458486
]}
459487
testID={testID}>
460488
<FlatList
489+
key={flatListRenderKey}
461490
ref={flatListRef}
462491
data={numbersForFlatList}
463492
decelerationRate={0.88}
@@ -479,7 +508,7 @@ const DurationScroll = forwardRef<DurationScrollRef, DurationScrollProps>(
479508
testID="duration-scroll-flatlist"
480509
viewabilityConfigCallbackPairs={
481510
!disableInfiniteScroll
482-
? viewabilityConfigCallbackPairs?.current
511+
? viewabilityConfigCallbackPairs
483512
: undefined
484513
}
485514
windowSize={numberOfItemsToShow}

0 commit comments

Comments
 (0)