mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add useHandleRef as a lighter alternative for useAnimatedRef (#6500)

authored by danabra.mov and committed by

GitHub 7b6c1827 4f0f9eb4

+75 -54
+39
src/lib/hooks/useHandleRef.ts
··· 1 + import {useState} from 'react' 2 + import {AnimatedRef, measure, MeasuredDimensions} from 'react-native-reanimated' 3 + 4 + export type HandleRef = { 5 + (node: any): void 6 + current: null | number 7 + } 8 + 9 + // This is a lighterweight alternative to `useAnimatedRef()` for imperative UI thread actions. 10 + // Render it like <View ref={ref} />, then pass `ref.current` to `measureHandle()` and such. 11 + export function useHandleRef(): HandleRef { 12 + return useState(() => { 13 + const ref = (node: any) => { 14 + if (node) { 15 + ref.current = 16 + node._nativeTag ?? 17 + node.__nativeTag ?? 18 + node.canonical?.nativeTag ?? 19 + null 20 + } else { 21 + ref.current = null 22 + } 23 + } 24 + ref.current = null 25 + return ref 26 + })[0] as HandleRef 27 + } 28 + 29 + // When using this version, you need to read ref.current on the JS thread, and pass it to UI. 30 + export function measureHandle( 31 + current: number | null, 32 + ): MeasuredDimensions | null { 33 + 'worklet' 34 + if (current !== null) { 35 + return measure((() => current) as AnimatedRef<any>) 36 + } else { 37 + return null 38 + } 39 + }
+7 -11
src/screens/Profile/Header/Shell.tsx
··· 1 1 import React, {memo} from 'react' 2 2 import {StyleSheet, TouchableWithoutFeedback, View} from 'react-native' 3 - import Animated, { 4 - measure, 5 - MeasuredDimensions, 6 - runOnJS, 7 - runOnUI, 8 - useAnimatedRef, 9 - } from 'react-native-reanimated' 3 + import {MeasuredDimensions, runOnJS, runOnUI} from 'react-native-reanimated' 10 4 import {AppBskyActorDefs, ModerationDecision} from '@atproto/api' 11 5 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' 12 6 import {msg} from '@lingui/macro' ··· 14 8 import {useNavigation} from '@react-navigation/native' 15 9 16 10 import {BACK_HITSLOP} from '#/lib/constants' 11 + import {measureHandle, useHandleRef} from '#/lib/hooks/useHandleRef' 17 12 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 18 13 import {NavigationProp} from '#/lib/routes/types' 19 14 import {isIOS} from '#/platform/detection' ··· 49 44 const {openLightbox} = useLightboxControls() 50 45 const navigation = useNavigation<NavigationProp>() 51 46 const {isDesktop} = useWebMediaQueries() 52 - const aviRef = useAnimatedRef() 47 + const aviRef = useHandleRef() 53 48 54 49 const onPressBack = React.useCallback(() => { 55 50 if (navigation.canGoBack()) { ··· 86 81 const modui = moderation.ui('avatar') 87 82 const avatar = profile.avatar 88 83 if (avatar && !(modui.blur && modui.noOverride)) { 84 + const aviHandle = aviRef.current 89 85 runOnUI(() => { 90 86 'worklet' 91 - const rect = measure(aviRef) 87 + const rect = measureHandle(aviHandle) 92 88 runOnJS(_openLightbox)(avatar, rect) 93 89 })() 94 90 } ··· 170 166 styles.avi, 171 167 profile.associated?.labeler && styles.aviLabeler, 172 168 ]}> 173 - <Animated.View ref={aviRef} collapsable={false}> 169 + <View ref={aviRef} collapsable={false}> 174 170 <UserAvatar 175 171 type={profile.associated?.labeler ? 'labeler' : 'user'} 176 172 size={90} 177 173 avatar={profile.avatar} 178 174 moderation={moderation.ui('avatar')} 179 175 /> 180 - </Animated.View> 176 + </View> 181 177 </View> 182 178 </TouchableWithoutFeedback> 183 179 </GrowableAvatar>
+7 -11
src/view/com/profile/ProfileSubpageHeader.tsx
··· 1 1 import React from 'react' 2 2 import {Pressable, StyleSheet, View} from 'react-native' 3 - import Animated, { 4 - measure, 5 - MeasuredDimensions, 6 - runOnJS, 7 - runOnUI, 8 - useAnimatedRef, 9 - } from 'react-native-reanimated' 3 + import {MeasuredDimensions, runOnJS, runOnUI} from 'react-native-reanimated' 10 4 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' 11 5 import {msg, Trans} from '@lingui/macro' 12 6 import {useLingui} from '@lingui/react' 13 7 import {useNavigation} from '@react-navigation/native' 14 8 15 9 import {BACK_HITSLOP} from '#/lib/constants' 10 + import {measureHandle, useHandleRef} from '#/lib/hooks/useHandleRef' 16 11 import {usePalette} from '#/lib/hooks/usePalette' 17 12 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 18 13 import {makeProfileLink} from '#/lib/routes/links' ··· 60 55 const {openLightbox} = useLightboxControls() 61 56 const pal = usePalette('default') 62 57 const canGoBack = navigation.canGoBack() 63 - const aviRef = useAnimatedRef() 58 + const aviRef = useHandleRef() 64 59 65 60 const onPressBack = React.useCallback(() => { 66 61 if (navigation.canGoBack()) { ··· 101 96 if ( 102 97 avatar // TODO && !(view.moderation.avatar.blur && view.moderation.avatar.noOverride) 103 98 ) { 99 + const aviHandle = aviRef.current 104 100 runOnUI(() => { 105 101 'worklet' 106 - const rect = measure(aviRef) 102 + const rect = measureHandle(aviHandle) 107 103 runOnJS(_openLightbox)(avatar, rect) 108 104 })() 109 105 } ··· 155 151 paddingBottom: 6, 156 152 paddingHorizontal: isMobile ? 12 : 14, 157 153 }}> 158 - <Animated.View ref={aviRef} collapsable={false}> 154 + <View ref={aviRef} collapsable={false}> 159 155 <Pressable 160 156 testID="headerAviButton" 161 157 onPress={onPressAvi} ··· 169 165 <UserAvatar type={avatarType} size={58} avatar={avatar} /> 170 166 )} 171 167 </Pressable> 172 - </Animated.View> 168 + </View> 173 169 <View style={{flex: 1}}> 174 170 {isLoading ? ( 175 171 <LoadingPlaceholder
+5 -8
src/view/com/util/images/AutoSizedImage.tsx
··· 1 1 import React, {useRef} from 'react' 2 2 import {DimensionValue, Pressable, View} from 'react-native' 3 - import Animated, {AnimatedRef, useAnimatedRef} from 'react-native-reanimated' 4 3 import {Image} from 'expo-image' 5 4 import {AppBskyEmbedImages} from '@atproto/api' 6 5 import {msg} from '@lingui/macro' 7 6 import {useLingui} from '@lingui/react' 8 7 8 + import {HandleRef, useHandleRef} from '#/lib/hooks/useHandleRef' 9 9 import type {Dimensions} from '#/lib/media/types' 10 10 import {isNative} from '#/platform/detection' 11 11 import {useLargeAltBadgeEnabled} from '#/state/preferences/large-alt-badge' ··· 68 68 image: AppBskyEmbedImages.ViewImage 69 69 crop?: 'none' | 'square' | 'constrained' 70 70 hideBadge?: boolean 71 - onPress?: ( 72 - containerRef: AnimatedRef<React.Component<{}, {}, any>>, 73 - fetchedDims: Dimensions | null, 74 - ) => void 71 + onPress?: (containerRef: HandleRef, fetchedDims: Dimensions | null) => void 75 72 onLongPress?: () => void 76 73 onPressIn?: () => void 77 74 }) { 78 75 const t = useTheme() 79 76 const {_} = useLingui() 80 77 const largeAlt = useLargeAltBadgeEnabled() 81 - const containerRef = useAnimatedRef() 78 + const containerRef = useHandleRef() 82 79 const fetchedDimsRef = useRef<{width: number; height: number} | null>(null) 83 80 84 81 let aspectRatio: number | undefined ··· 109 106 const hasAlt = !!image.alt 110 107 111 108 const contents = ( 112 - <Animated.View ref={containerRef} collapsable={false} style={{flex: 1}}> 109 + <View ref={containerRef} collapsable={false} style={{flex: 1}}> 113 110 <Image 114 111 style={[a.w_full, a.h_full]} 115 112 source={image.thumb} ··· 188 185 )} 189 186 </View> 190 187 ) : null} 191 - </Animated.View> 188 + </View> 192 189 ) 193 190 194 191 if (cropDisabled) {
+5 -8
src/view/com/util/images/Gallery.tsx
··· 1 1 import React from 'react' 2 2 import {Pressable, StyleProp, View, ViewStyle} from 'react-native' 3 - import Animated, {AnimatedRef} from 'react-native-reanimated' 4 3 import {Image, ImageStyle} from 'expo-image' 5 4 import {AppBskyEmbedImages} from '@atproto/api' 6 5 import {msg} from '@lingui/macro' 7 6 import {useLingui} from '@lingui/react' 8 7 8 + import {HandleRef} from '#/lib/hooks/useHandleRef' 9 9 import {Dimensions} from '#/lib/media/types' 10 10 import {useLargeAltBadgeEnabled} from '#/state/preferences/large-alt-badge' 11 11 import {PostEmbedViewContext} from '#/view/com/util/post-embeds/types' ··· 20 20 index: number 21 21 onPress?: ( 22 22 index: number, 23 - containerRefs: AnimatedRef<React.Component<{}, {}, any>>[], 23 + containerRefs: HandleRef[], 24 24 fetchedDims: (Dimensions | null)[], 25 25 ) => void 26 26 onLongPress?: EventFunction ··· 28 28 imageStyle?: StyleProp<ImageStyle> 29 29 viewContext?: PostEmbedViewContext 30 30 insetBorderStyle?: StyleProp<ViewStyle> 31 - containerRefs: AnimatedRef<React.Component<{}, {}, any>>[] 31 + containerRefs: HandleRef[] 32 32 thumbDimsRef: React.MutableRefObject<(Dimensions | null)[]> 33 33 } 34 34 ··· 52 52 const hideBadges = 53 53 viewContext === PostEmbedViewContext.FeedEmbedRecordWithMedia 54 54 return ( 55 - <Animated.View 56 - style={a.flex_1} 57 - ref={containerRefs[index]} 58 - collapsable={false}> 55 + <View style={a.flex_1} ref={containerRefs[index]} collapsable={false}> 59 56 <Pressable 60 57 onPress={ 61 58 onPress ··· 118 115 </Text> 119 116 </View> 120 117 ) : null} 121 - </Animated.View> 118 + </View> 122 119 ) 123 120 }
+7 -7
src/view/com/util/images/ImageLayoutGrid.tsx
··· 1 1 import React from 'react' 2 2 import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native' 3 - import {AnimatedRef, useAnimatedRef} from 'react-native-reanimated' 4 3 import {AppBskyEmbedImages} from '@atproto/api' 5 4 5 + import {HandleRef, useHandleRef} from '#/lib/hooks/useHandleRef' 6 6 import {PostEmbedViewContext} from '#/view/com/util/post-embeds/types' 7 7 import {atoms as a, useBreakpoints} from '#/alf' 8 8 import {Dimensions} from '../../lightbox/ImageViewing/@types' ··· 12 12 images: AppBskyEmbedImages.ViewImage[] 13 13 onPress?: ( 14 14 index: number, 15 - containerRefs: AnimatedRef<React.Component<{}, {}, any>>[], 15 + containerRefs: HandleRef[], 16 16 fetchedDims: (Dimensions | null)[], 17 17 ) => void 18 18 onLongPress?: (index: number) => void ··· 43 43 images: AppBskyEmbedImages.ViewImage[] 44 44 onPress?: ( 45 45 index: number, 46 - containerRefs: AnimatedRef<React.Component<{}, {}, any>>[], 46 + containerRefs: HandleRef[], 47 47 fetchedDims: (Dimensions | null)[], 48 48 ) => void 49 49 onLongPress?: (index: number) => void ··· 56 56 const gap = props.gap 57 57 const count = props.images.length 58 58 59 - const containerRef1 = useAnimatedRef() 60 - const containerRef2 = useAnimatedRef() 61 - const containerRef3 = useAnimatedRef() 62 - const containerRef4 = useAnimatedRef() 59 + const containerRef1 = useHandleRef() 60 + const containerRef2 = useHandleRef() 61 + const containerRef3 = useHandleRef() 62 + const containerRef4 = useHandleRef() 63 63 const thumbDimsRef = React.useRef<(Dimensions | null)[]>([]) 64 64 65 65 switch (count) {
+5 -9
src/view/com/util/post-embeds/index.tsx
··· 6 6 View, 7 7 ViewStyle, 8 8 } from 'react-native' 9 - import { 10 - AnimatedRef, 11 - measure, 12 - MeasuredDimensions, 13 - runOnJS, 14 - runOnUI, 15 - } from 'react-native-reanimated' 9 + import {MeasuredDimensions, runOnJS, runOnUI} from 'react-native-reanimated' 16 10 import {Image} from 'expo-image' 17 11 import { 18 12 AppBskyEmbedExternal, ··· 27 21 ModerationDecision, 28 22 } from '@atproto/api' 29 23 24 + import {HandleRef, measureHandle} from '#/lib/hooks/useHandleRef' 30 25 import {usePalette} from '#/lib/hooks/usePalette' 31 26 import {useLightboxControls} from '#/state/lightbox' 32 27 import {useModerationOpts} from '#/state/preferences/moderation-opts' ··· 163 158 } 164 159 const onPress = ( 165 160 index: number, 166 - refs: AnimatedRef<React.Component<{}, {}, any>>[], 161 + refs: HandleRef[], 167 162 fetchedDims: (Dimensions | null)[], 168 163 ) => { 164 + const handles = refs.map(r => r.current) 169 165 runOnUI(() => { 170 166 'worklet' 171 - const rects = refs.map(ref => (ref ? measure(ref) : null)) 167 + const rects = handles.map(measureHandle) 172 168 runOnJS(_openLightbox)(index, rects, fetchedDims) 173 169 })() 174 170 }