Forked from intergalacticspacehighway/viewability-tracker-flatlist.tsx
Created
January 25, 2022 14:42
-
-
Save hirbod/bb33b4a933934ae6160ac4744d499da9 to your computer and use it in GitHub Desktop.
Viewability tracker with shared values
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { createContext, forwardRef, useCallback, useMemo } from "react"; | |
import { FlatList, FlatListProps, ViewToken } from "react-native"; | |
import Animated, { useSharedValue } from "react-native-reanimated"; | |
const MAX_VIEWABLE_ITEMS = 4; | |
type ViewabilityItemsContextType = string[]; | |
export const ViewabilityItemsContext = createContext< | |
Animated.SharedValue<ViewabilityItemsContextType> | |
>({ | |
value: [], | |
}); | |
export const ViewabilityTrackerFlatlist = forwardRef( | |
(props: FlatListProps<any>, ref: any) => { | |
const visibleItems = useSharedValue<ViewabilityItemsContextType>([]); | |
const { keyExtractor, renderItem: _renderItem } = props; | |
const renderItem = useCallback( | |
(params: any) => ( | |
<ItemKeyContext.Provider | |
value={keyExtractor?.(params.item, params.index)} | |
> | |
{_renderItem?.(params)} | |
</ItemKeyContext.Provider> | |
), | |
[_renderItem, keyExtractor] | |
); | |
const onViewableItemsChanged = useCallback(({ viewableItems }: any) => { | |
visibleItems.value = viewableItems | |
.slice(0, MAX_VIEWABLE_ITEMS) | |
.map((item: any) => item.key); | |
}, []); | |
return ( | |
<ViewabilityItemsContext.Provider value={visibleItems}> | |
<FlatList | |
{...props} | |
onViewableItemsChanged={onViewableItemsChanged} | |
ref={ref} | |
viewabilityConfig={useMemo( | |
() => ({ | |
itemVisiblePercentThreshold: 50, | |
minimumViewTime: 100, | |
}), | |
[] | |
)} | |
renderItem={renderItem} | |
/> | |
</ViewabilityItemsContext.Provider> | |
); | |
} | |
); | |
export const ItemKeyContext = createContext<string | undefined>(undefined); | |
// Usage in item to do stuff. | |
export const useDoSomethingWhenItemVisible = () => { | |
const id = useContext(ItemKeyContext); | |
const context = useContext(ViewabilityItemsContext); | |
// we mount or unmount the Video depending on the list visibility state | |
useAnimatedReaction( | |
() => context.value, | |
(ctx) => { | |
if (ctx.includes(id)) { | |
// do stuff on item visible | |
} else if (!ctx.includes(id)) { | |
// do stuff on item invisible | |
} | |
}, | |
[] | |
); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment