import React, { useContext, useEffect } from "react"; import { useMemo, useRef } from "react"; import { FlatList } from "react-native-gesture-handler"; import Animated, { type SharedValue, useSharedValue, WithSpringConfig } from "react-native-reanimated"; import { DEFAULT_PROPS } from "../constants"; import { useProps } from "./propsContext"; import { CellData, DraggableFlatListProps } from "../types"; type RefContextValue = { propsRef: React.MutableRefObject>; animationConfigRef: SharedValue; cellDataRef: React.MutableRefObject>; keyToIndexRef: React.MutableRefObject>; containerRef: React.RefObject; flatlistRef: React.RefObject> | React.ForwardedRef>; scrollViewRef: React.RefObject; }; const RefContext = React.createContext | undefined>( undefined ); export default function RefProvider({ children, flatListRef, }: { children: React.ReactNode; flatListRef?: React.ForwardedRef> | null; }) { const value = useSetupRefs({ flatListRef }); return {children}; } export function useRefs() { const value = useContext(RefContext); if (!value) { throw new Error( "useRefs must be called from within a RefContext.Provider!" ); } return value as RefContextValue; } function useSetupRefs({ flatListRef: flatListRefProp, }: { flatListRef?: React.ForwardedRef> | null; }) { const props = useProps(); const { animationConfig = DEFAULT_PROPS.animationConfig } = props; const propsRef = useRef(props); propsRef.current = props; const animConfig = useMemo( () => ({ ...DEFAULT_PROPS.animationConfig, ...animationConfig, } as WithSpringConfig), [animationConfig] ); const animationConfigRef = useSharedValue(animConfig); useEffect(() => { animationConfigRef.value = animConfig; }, [animConfig]); const cellDataRef = useRef(new Map()); const keyToIndexRef = useRef(new Map()); const containerRef = useRef(null); const flatlistRefInternal = useRef>(null); const flatlistRef = flatListRefProp || flatlistRefInternal; const scrollViewRef = useRef(null); // useEffect(() => { // // This is a workaround for the fact that RN does not respect refs passed in // // to renderScrollViewComponent underlying ScrollView (currently not used but // // may need to add if we want to use reanimated scrollTo in the future) // //@ts-ignore // const scrollRef = flatlistRef.current?.getNativeScrollRef(); // if (!scrollViewRef.current) { // //@ts-ignore // scrollViewRef(scrollRef); // } // }, []); const refs = useMemo( () => ({ animationConfigRef, cellDataRef, containerRef, flatlistRef, keyToIndexRef, propsRef, scrollViewRef, }), [] ); return refs; }