UNPKG

react-native-use-in-view

Version:

A versatile and efficient React Native component designed for seamless integration of scroll-based features into mobile applications. This package offers a powerful ScrollView observer that allows developers to easily track and respond to scroll events an

100 lines 5.08 kB
import React, { createContext, forwardRef, useCallback, useContext, useEffect, useRef, useState, } from 'react'; import { FlatList, ScrollView, } from 'react-native'; const ViewContext = createContext(null); /** * Hook to detect if an element is in the viewport. * The `ref` must be attached to a native component (e.g., View, Text) or a custom component that forwards the ref to a native component. */ export const useInView = (options) => { const { initialInView = false, threshold = 0, triggerOnce = false } = options || {}; const [inView, setInView] = useState(initialInView); const elementRef = useRef(null); const scrollContext = useContext(ViewContext); const checkInView = useCallback(() => { if (!elementRef.current?.measureInWindow) return; if (!scrollContext?.scrollViewRect) { console.warn('useInView: Scroll context is not available. Ensure useInView is used within a ScrollViewObserver or FlatListObserver.'); return; } const { scrollViewRect } = scrollContext; const { x: scrollViewX, y: scrollViewY, width: scrollViewWidth, height: scrollViewHeight, } = scrollViewRect; elementRef.current.measureInWindow((x, y, width, height) => { const elementRight = x + width; const elementBottom = y + height; const isVisible = elementRight > scrollViewX - threshold && elementBottom > scrollViewY - threshold && x < scrollViewX + scrollViewWidth + threshold && y < scrollViewY + scrollViewHeight + threshold; if (isVisible && !inView) setInView(true); else if (!isVisible && !triggerOnce && inView) setInView(false); }); }, [inView, threshold]); useEffect(() => { const timeout = setTimeout(checkInView, 0); return () => clearTimeout(timeout); }, [checkInView]); useEffect(() => { if (scrollContext) scrollContext.registerScrollListener(checkInView); return () => { if (scrollContext) scrollContext.unregisterScrollListener(checkInView); }; }, [scrollContext, checkInView]); return { ref: elementRef, inView }; }; /** * Generic hook to manage scroll listeners. */ const useScrollListeners = (options) => { const listeners = useRef(new Set()); const internalRef = useRef(null); const refToUse = (options.ref ?? internalRef); const [scrollViewRect, setScrollViewRect] = useState({ x: 0, y: 0, width: 0, height: 0 }); const registerScrollListener = useCallback((listener) => { listeners.current.add(listener); }, []); const unregisterScrollListener = useCallback((listener) => { listeners.current.delete(listener); }, []); const handleScroll = useCallback((event) => { listeners.current.forEach((listener) => listener()); }, []); const handleLayout = (event) => { setScrollViewRect(event.nativeEvent.layout); if (options.onLayout) options.onLayout(event); }; return { scrollRef: refToUse, scrollViewRect, registerScrollListener, unregisterScrollListener, handleScroll, handleLayout, }; }; /** * Implementation of a ScrollView with in-view detection and scroll listeners. * This component is used to wrap a ScrollView and provide in-view detection for its children. * It takes all the props of a standard ScrollView and forwards the ref to the internal ScrollView. */ export const ScrollViewObserver = forwardRef(({ scrollEventThrottle = 100, onScroll, onLayout, ...rest }, ref) => { const { scrollRef, scrollViewRect, registerScrollListener, unregisterScrollListener, handleScroll, handleLayout, } = useScrollListeners({ ref, onLayout }); return (React.createElement(ViewContext.Provider, { value: { registerScrollListener, unregisterScrollListener, scrollViewRect, scrollRef } }, React.createElement(ScrollView, { ref: scrollRef, onLayout: handleLayout, onScroll: handleScroll, scrollEventThrottle: scrollEventThrottle, ...rest }))); }); /** * Implementation of a FlatList with in-view detection and scroll listeners. * This component is used to wrap a FlatList and provide in-view detection for its children. * It takes all the props of a standard FlatList and forwards the ref to the internal FlatList. */ export const FlatListObserver = ({ scrollEventThrottle = 100, flatListRef, onLayout, onScroll, ...rest }) => { const { scrollRef, scrollViewRect, registerScrollListener, unregisterScrollListener, handleScroll, handleLayout, } = useScrollListeners({ ref: flatListRef, onLayout }); return (React.createElement(ViewContext.Provider, { value: { registerScrollListener, unregisterScrollListener, scrollViewRect, scrollRef } }, React.createElement(FlatList, { ref: scrollRef, onLayout: handleLayout, onScroll: handleScroll, scrollEventThrottle: scrollEventThrottle, ...rest }))); }; //# sourceMappingURL=index.js.map