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 <dan.abramov@gmail.com>
This commit is contained in:
@@ -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 (
|
||||
<KeyboardProvider
|
||||
enabled={false}
|
||||
// I don't think this is necessary, but Chesterton's fence and all that -sfn
|
||||
statusBarTranslucent={true}>
|
||||
<KeyboardControllerProviderInner>
|
||||
{children}
|
||||
</KeyboardControllerProviderInner>
|
||||
</KeyboardProvider>
|
||||
)
|
||||
}
|
||||
|
||||
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 (
|
||||
<KeyboardControllerRefCountContext.Provider value={value}>
|
||||
{children}
|
||||
</KeyboardControllerRefCountContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
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]),
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user