Lazily measure lightbox thumbnails (#10270)
This commit is contained in:
+39
-8
@@ -1,4 +1,10 @@
|
||||
import {createContext, useContext, useEffect, useMemo, useState} from 'react'
|
||||
import {
|
||||
measure,
|
||||
type MeasuredDimensions,
|
||||
runOnJS,
|
||||
runOnUI,
|
||||
} from 'react-native-reanimated'
|
||||
import {nanoid} from 'nanoid/non-secure'
|
||||
|
||||
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
||||
@@ -39,17 +45,42 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||
}
|
||||
}, [activeLightbox, disableScope, enableScope])
|
||||
|
||||
const doOpen = useNonReactiveCallback((lightbox: Omit<Lightbox, 'id'>) => {
|
||||
setActiveLightbox(prevLightbox => {
|
||||
if (prevLightbox) {
|
||||
// Ignore duplicate open requests. If it's already open,
|
||||
// the user has to explicitly close the previous one first.
|
||||
return prevLightbox
|
||||
} else {
|
||||
return {...lightbox, id: nanoid()}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const openLightbox = useNonReactiveCallback(
|
||||
(lightbox: Omit<Lightbox, 'id'>) => {
|
||||
setActiveLightbox(prevLightbox => {
|
||||
if (prevLightbox) {
|
||||
// Ignore duplicate open requests. If it's already open,
|
||||
// the user has to explicitly close the previous one first.
|
||||
return prevLightbox
|
||||
} else {
|
||||
return {...lightbox, id: nanoid()}
|
||||
const thumbRef = lightbox.images[lightbox.index]?.thumbRef
|
||||
if (thumbRef) {
|
||||
// Measure the tapped image on the UI thread, then open with
|
||||
// the rect baked in so it's available from the first render.
|
||||
// Only the rect (plain data) goes through runOnJS — AnimatedRef
|
||||
// objects can't survive serialization across threads.
|
||||
const openWithRect = (rect: MeasuredDimensions | null) => {
|
||||
doOpen({
|
||||
...lightbox,
|
||||
images: lightbox.images.map((img, i) =>
|
||||
i === lightbox.index ? {...img, thumbRect: rect} : img,
|
||||
),
|
||||
})
|
||||
}
|
||||
})
|
||||
runOnUI(() => {
|
||||
'worklet'
|
||||
const rect = measure(thumbRef)
|
||||
runOnJS(openWithRect)(rect)
|
||||
})()
|
||||
} else {
|
||||
doOpen(lightbox)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user