From 3043b324681f1702ca53831701fb5cecd14c0efb Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 17 Nov 2023 02:01:51 +0000 Subject: [PATCH] Fix jumpy modal regression (#1945) --- src/lib/hooks/useNonReactiveCallback.ts | 23 +++++++++++++++++++++++ src/view/com/modals/Modal.tsx | 16 ++++++++++------ 2 files changed, 33 insertions(+), 6 deletions(-) create mode 100644 src/lib/hooks/useNonReactiveCallback.ts diff --git a/src/lib/hooks/useNonReactiveCallback.ts b/src/lib/hooks/useNonReactiveCallback.ts new file mode 100644 index 00000000..4b3d6abb --- /dev/null +++ b/src/lib/hooks/useNonReactiveCallback.ts @@ -0,0 +1,23 @@ +import {useCallback, useInsertionEffect, useRef} from 'react' + +// This should be used sparingly. It erases reactivity, i.e. when the inputs +// change, the function itself will remain the same. This means that if you +// use this at a higher level of your tree, and then some state you read in it +// changes, there is no mechanism for anything below in the tree to "react" +// to this change (e.g. by knowing to call your function again). +// +// Also, you should avoid calling the returned function during rendering +// since the values captured by it are going to lag behind. +export function useNonReactiveCallback(fn: T): T { + const ref = useRef(fn) + useInsertionEffect(() => { + ref.current = fn + }, [fn]) + return useCallback( + (...args: any) => { + const latestFn = ref.current + return latestFn(...args) + }, + [ref], + ) as unknown as T +} diff --git a/src/view/com/modals/Modal.tsx b/src/view/com/modals/Modal.tsx index d834db40..a3e6fb9e 100644 --- a/src/view/com/modals/Modal.tsx +++ b/src/view/com/modals/Modal.tsx @@ -9,6 +9,7 @@ import {navigate} from '../../../Navigation' import once from 'lodash.once' import {useModals, useModalControls} from '#/state/modals' +import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' import * as ConfirmModal from './Confirm' import * as EditProfileModal from './EditProfile' import * as ProfilePreviewModal from './ProfilePreview' @@ -50,12 +51,15 @@ export function ModalsContainer() { const navigateOnce = once(navigate) - const onBottomSheetAnimate = (_fromIndex: number, toIndex: number) => { - if (activeModal?.name === 'profile-preview' && toIndex === 1) { - // begin loading the profile screen behind the scenes - navigateOnce('Profile', {name: activeModal.did}) - } - } + // It seems like the bottom sheet bugs out when this callback changes. + const onBottomSheetAnimate = useNonReactiveCallback( + (_fromIndex: number, toIndex: number) => { + if (activeModal?.name === 'profile-preview' && toIndex === 1) { + // begin loading the profile screen behind the scenes + navigateOnce('Profile', {name: activeModal.did}) + } + }, + ) const onBottomSheetChange = async (snapPoint: number) => { if (snapPoint === -1) { closeModal()