about summary refs log tree commit diff
diff options
context:
space:
mode:
authordan <dan.abramov@gmail.com>2024-11-18 21:42:32 +0000
committerGitHub <noreply@github.com>2024-11-18 21:42:32 +0000
commitec973522015b7a83262184f0775d04ef784f53ff (patch)
tree3d644a3c8ec7493602a66e3121c87e3168423181
parent924f1e0e7f097b38081256920c71ddcc3f4ec85f (diff)
downloadvoidsky-ec973522015b7a83262184f0775d04ef784f53ff.tar.zst
Fix layout jumps for images (#6474)
-rw-r--r--src/view/com/util/images/AutoSizedImage.tsx27
1 files changed, 15 insertions, 12 deletions
diff --git a/src/view/com/util/images/AutoSizedImage.tsx b/src/view/com/util/images/AutoSizedImage.tsx
index fe8911e31..0ecbb3597 100644
--- a/src/view/com/util/images/AutoSizedImage.tsx
+++ b/src/view/com/util/images/AutoSizedImage.tsx
@@ -1,4 +1,4 @@
-import React from 'react'
+import React, {useRef} from 'react'
 import {DimensionValue, Pressable, View} from 'react-native'
 import Animated, {AnimatedRef, useAnimatedRef} from 'react-native-reanimated'
 import {Image} from 'expo-image'
@@ -79,15 +79,19 @@ export function AutoSizedImage({
   const {_} = useLingui()
   const largeAlt = useLargeAltBadgeEnabled()
   const containerRef = useAnimatedRef()
+  const fetchedDimsRef = useRef<{width: number; height: number} | null>(null)
 
-  const [fetchedDims, setFetchedDims] = React.useState<Dimensions | null>(null)
-  const dims = fetchedDims ?? image.aspectRatio
   let aspectRatio: number | undefined
+  const dims = image.aspectRatio
   if (dims) {
     aspectRatio = dims.width / dims.height
     if (Number.isNaN(aspectRatio)) {
       aspectRatio = undefined
     }
+  } else {
+    // If we don't know it synchronously, treat it like a square.
+    // We won't use fetched dimensions to avoid a layout shift.
+    aspectRatio = 1
   }
 
   let constrained: number | undefined
@@ -113,13 +117,12 @@ export function AutoSizedImage({
         accessibilityIgnoresInvertColors
         accessibilityLabel={image.alt}
         accessibilityHint=""
-        onLoad={
-          fetchedDims
-            ? undefined
-            : e => {
-                setFetchedDims({width: e.source.width, height: e.source.height})
-              }
-        }
+        onLoad={e => {
+          fetchedDimsRef.current = {
+            width: e.source.width,
+            height: e.source.height,
+          }
+        }}
       />
       <MediaInsetBorder />
 
@@ -191,7 +194,7 @@ export function AutoSizedImage({
   if (cropDisabled) {
     return (
       <Pressable
-        onPress={() => onPress?.(containerRef, fetchedDims)}
+        onPress={() => onPress?.(containerRef, fetchedDimsRef.current)}
         onLongPress={onLongPress}
         onPressIn={onPressIn}
         // alt here is what screen readers actually use
@@ -213,7 +216,7 @@ export function AutoSizedImage({
         fullBleed={crop === 'square'}
         aspectRatio={constrained ?? 1}>
         <Pressable
-          onPress={() => onPress?.(containerRef, fetchedDims)}
+          onPress={() => onPress?.(containerRef, fetchedDimsRef.current)}
           onLongPress={onLongPress}
           onPressIn={onPressIn}
           // alt here is what screen readers actually use