Forked from intergalacticspacehighway/viewability-tracker-flatlist.tsx
Created
January 21, 2025 02:12
-
-
Save chanphiromsok/0f09e8ca9b2be9f6701c69cfb4988422 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