Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save a-eid/2b2892957f50ecf11cfece72af2ba0fd to your computer and use it in GitHub Desktop.
Save a-eid/2b2892957f50ecf11cfece72af2ba0fd to your computer and use it in GitHub Desktop.
Viewability tracker with shared values
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