From b0c36383a9a7304f94c2bb19f7cc4b37e0b4f637 Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Mon, 25 Nov 2024 20:30:15 +0000 Subject: Ensure react-native-keyboard-controller enabled state doesn't get overwritten (#6727) * revert to prev state instead of false * add dep array * use ref counting approach * patch keyboard controller to allow changing the enabled prop * remove state from patch * change patched prop name * remove Math.max check, log if < 0 * use noop provider * rm patch, use `useRef` * Style nits * Rm on web --------- Co-authored-by: Dan Abramov --- src/lib/hooks/useEnableKeyboardController.tsx | 110 ++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 src/lib/hooks/useEnableKeyboardController.tsx (limited to 'src/lib/hooks/useEnableKeyboardController.tsx') diff --git a/src/lib/hooks/useEnableKeyboardController.tsx b/src/lib/hooks/useEnableKeyboardController.tsx new file mode 100644 index 000000000..c7205d016 --- /dev/null +++ b/src/lib/hooks/useEnableKeyboardController.tsx @@ -0,0 +1,110 @@ +import { + createContext, + useCallback, + useContext, + useEffect, + useMemo, + useRef, +} from 'react' +import { + KeyboardProvider, + useKeyboardController, +} from 'react-native-keyboard-controller' +import {useFocusEffect} from '@react-navigation/native' + +import {IS_DEV} from '#/env' + +const KeyboardControllerRefCountContext = createContext<{ + incrementRefCount: () => void + decrementRefCount: () => void +}>({ + incrementRefCount: () => {}, + decrementRefCount: () => {}, +}) + +export function KeyboardControllerProvider({ + children, +}: { + children: React.ReactNode +}) { + return ( + + + {children} + + + ) +} + +function KeyboardControllerProviderInner({ + children, +}: { + children: React.ReactNode +}) { + const {setEnabled} = useKeyboardController() + const refCount = useRef(0) + + const value = useMemo( + () => ({ + incrementRefCount: () => { + refCount.current++ + setEnabled(refCount.current > 0) + }, + decrementRefCount: () => { + refCount.current-- + setEnabled(refCount.current > 0) + + if (IS_DEV && refCount.current < 0) { + console.error('KeyboardController ref count < 0') + } + }, + }), + [setEnabled], + ) + + return ( + + {children} + + ) +} + +export function useEnableKeyboardController(shouldEnable: boolean) { + const {incrementRefCount, decrementRefCount} = useContext( + KeyboardControllerRefCountContext, + ) + + useEffect(() => { + if (!shouldEnable) { + return + } + incrementRefCount() + return () => { + decrementRefCount() + } + }, [shouldEnable, incrementRefCount, decrementRefCount]) +} + +/** + * Like `useEnableKeyboardController`, but using `useFocusEffect` + */ +export function useEnableKeyboardControllerScreen(shouldEnable: boolean) { + const {incrementRefCount, decrementRefCount} = useContext( + KeyboardControllerRefCountContext, + ) + + useFocusEffect( + useCallback(() => { + if (!shouldEnable) { + return + } + incrementRefCount() + return () => { + decrementRefCount() + } + }, [shouldEnable, incrementRefCount, decrementRefCount]), + ) +} -- cgit 1.4.1