UNPKG

3.22 kBPlain TextView Raw
1'use strict';
2import type { Component } from 'react';
3import { useRef } from 'react';
4import { useSharedValue } from './useSharedValue';
5import type { AnimatedRef, AnimatedRefOnUI } from './commonTypes';
6import type { ShadowNodeWrapper } from '../commonTypes';
7import { getShadowNodeWrapperFromRef } from '../fabricUtils';
8import { makeShareableCloneRecursive } from '../shareables';
9import { shareableMappingCache } from '../shareableMappingCache';
10import { Platform, findNodeHandle } from 'react-native';
11import type { ScrollView, FlatList } from 'react-native';
12import { isFabric, isWeb } from '../PlatformChecker';
13
14const IS_WEB = isWeb();
15
16interface MaybeScrollableComponent extends Component {
17 getNativeScrollRef?: FlatList['getNativeScrollRef'];
18 getScrollableNode?:
19 | ScrollView['getScrollableNode']
20 | FlatList['getScrollableNode'];
21 viewConfig?: {
22 uiViewClassName?: string;
23 };
24}
25
26function getComponentOrScrollable(component: MaybeScrollableComponent) {
27 if (isFabric() && component.getNativeScrollRef) {
28 return component.getNativeScrollRef();
29 } else if (!isFabric() && component.getScrollableNode) {
30 return component.getScrollableNode();
31 }
32 return component;
33}
34
35/**
36 * Lets you get a reference of a view that you can use inside a worklet.
37 *
38 * @returns An object with a `.current` property which contains an instance of a component.
39 * @see https://docs.swmansion.com/react-native-reanimated/docs/core/useAnimatedRef
40 */
41export function useAnimatedRef<
42 TComponent extends Component
43>(): AnimatedRef<TComponent> {
44 const tag = useSharedValue<number | ShadowNodeWrapper | null>(-1);
45 const viewName = useSharedValue<string | null>(null);
46
47 const ref = useRef<AnimatedRef<TComponent>>();
48
49 if (!ref.current) {
50 const fun: AnimatedRef<TComponent> = <AnimatedRef<TComponent>>((
51 component
52 ) => {
53 // enters when ref is set by attaching to a component
54 if (component) {
55 const getTagValueFunction = isFabric()
56 ? getShadowNodeWrapperFromRef
57 : findNodeHandle;
58
59 const getTagOrShadowNodeWrapper = () => {
60 return IS_WEB
61 ? getComponentOrScrollable(component)
62 : getTagValueFunction(getComponentOrScrollable(component));
63 };
64
65 tag.value = getTagOrShadowNodeWrapper();
66
67 // On Fabric we have to unwrap the tag from the shadow node wrapper
68 fun.getTag = isFabric()
69 ? () => findNodeHandle(getComponentOrScrollable(component))
70 : getTagOrShadowNodeWrapper;
71
72 fun.current = component;
73 // viewName is required only on iOS with Paper
74 if (Platform.OS === 'ios' && !isFabric()) {
75 viewName.value =
76 (component as MaybeScrollableComponent)?.viewConfig
77 ?.uiViewClassName || 'RCTView';
78 }
79 }
80 return tag.value;
81 });
82
83 fun.current = null;
84
85 const animatedRefShareableHandle = makeShareableCloneRecursive({
86 __init: () => {
87 'worklet';
88 const f: AnimatedRefOnUI = () => tag.value;
89 f.viewName = viewName;
90 return f;
91 },
92 });
93 shareableMappingCache.set(fun, animatedRefShareableHandle);
94 ref.current = fun;
95 }
96
97 return ref.current;
98}