fix: make sure we don't miss dimensions updates

This commit is contained in:
Satyajit Sahoo
2020-06-24 22:09:00 +02:00
parent d85d27c432
commit c65f9ef1a9
5 changed files with 111 additions and 56 deletions

View File

@@ -0,0 +1,31 @@
import * as React from 'react';
import { Keyboard, Platform } from 'react-native';
export default function useIsKeyboardShown() {
const [isKeyboardShown, setIsKeyboardShown] = React.useState(false);
React.useEffect(() => {
const handleKeyboardShow = () => setIsKeyboardShown(true);
const handleKeyboardHide = () => setIsKeyboardShown(false);
if (Platform.OS === 'ios') {
Keyboard.addListener('keyboardWillShow', handleKeyboardShow);
Keyboard.addListener('keyboardWillHide', handleKeyboardHide);
} else {
Keyboard.addListener('keyboardDidShow', handleKeyboardShow);
Keyboard.addListener('keyboardDidHide', handleKeyboardHide);
}
return () => {
if (Platform.OS === 'ios') {
Keyboard.removeListener('keyboardWillShow', handleKeyboardShow);
Keyboard.removeListener('keyboardWillHide', handleKeyboardHide);
} else {
Keyboard.removeListener('keyboardDidShow', handleKeyboardShow);
Keyboard.removeListener('keyboardDidHide', handleKeyboardHide);
}
};
}, []);
return isKeyboardShown;
}

View File

@@ -0,0 +1,37 @@
import * as React from 'react';
import { ScaledSize, Dimensions } from 'react-native';
// This is similar to the new useWindowDimensions hook in react-native
// However, we have a custom implementation to support older RN versions
export default function useWindowDimensions() {
const [dimensions, setDimensions] = React.useState(() => {
// `height` and `width` maybe undefined during SSR, so we initialize them
const { height = 0, width = 0 } = Dimensions.get('window');
return { height, width };
});
React.useEffect(() => {
const onChange = ({ window }: { window: ScaledSize }) => {
const { width, height } = window;
setDimensions((d) => {
if (width === d.width && height === d.height) {
return d;
}
return { width, height };
});
};
// We might have missed an update before the listener was added
// So make sure to update the dimensions
onChange({ window: Dimensions.get('window') });
Dimensions.addEventListener('change', onChange);
return () => Dimensions.addEventListener('change', onChange);
}, []);
return dimensions;
}

View File

@@ -3,11 +3,8 @@ import {
View,
Animated,
StyleSheet,
Keyboard,
Platform,
LayoutChangeEvent,
ScaledSize,
Dimensions,
} from 'react-native';
import {
NavigationContext,
@@ -19,6 +16,8 @@ import {
import { useSafeArea } from 'react-native-safe-area-context';
import BottomTabItem from './BottomTabItem';
import useWindowDimensions from '../utils/useWindowDimensions';
import useIsKeyboardShown from '../utils/useIsKeyboardShown';
import type { BottomTabBarProps } from '../types';
type Props = BottomTabBarProps & {
@@ -57,7 +56,8 @@ export default function BottomTabBar({
const focusedDescriptor = descriptors[focusedRoute.key];
const focusedOptions = focusedDescriptor.options;
const [isKeyboardShown, setIsKeyboardShown] = React.useState(false);
const dimensions = useWindowDimensions();
const isKeyboardShown = useIsKeyboardShown();
const shouldShowTabBar =
focusedOptions.tabBarVisible !== false &&
@@ -91,43 +91,6 @@ export default function BottomTabBar({
}
}, [shouldShowTabBar, visible]);
const [dimensions, setDimensions] = React.useState(() => {
const { height = 0, width = 0 } = Dimensions.get('window');
return { height, width };
});
React.useEffect(() => {
const handleOrientationChange = ({ window }: { window: ScaledSize }) => {
setDimensions(window);
};
Dimensions.addEventListener('change', handleOrientationChange);
const handleKeyboardShow = () => setIsKeyboardShown(true);
const handleKeyboardHide = () => setIsKeyboardShown(false);
if (Platform.OS === 'ios') {
Keyboard.addListener('keyboardWillShow', handleKeyboardShow);
Keyboard.addListener('keyboardWillHide', handleKeyboardHide);
} else {
Keyboard.addListener('keyboardDidShow', handleKeyboardShow);
Keyboard.addListener('keyboardDidHide', handleKeyboardHide);
}
return () => {
Dimensions.removeEventListener('change', handleOrientationChange);
if (Platform.OS === 'ios') {
Keyboard.removeListener('keyboardWillShow', handleKeyboardShow);
Keyboard.removeListener('keyboardWillHide', handleKeyboardHide);
} else {
Keyboard.removeListener('keyboardDidShow', handleKeyboardShow);
Keyboard.removeListener('keyboardDidHide', handleKeyboardHide);
}
};
}, []);
const [layout, setLayout] = React.useState({
height: 0,
width: dimensions.width,

View File

@@ -0,0 +1,37 @@
import * as React from 'react';
import { ScaledSize, Dimensions } from 'react-native';
// This is similar to the new useWindowDimensions hook in react-native
// However, we have a custom implementation to support older RN versions
export default function useWindowDimensions() {
const [dimensions, setDimensions] = React.useState(() => {
// `height` and `width` maybe undefined during SSR, so we initialize them
const { height = 0, width = 0 } = Dimensions.get('window');
return { height, width };
});
React.useEffect(() => {
const onChange = ({ window }: { window: ScaledSize }) => {
const { width, height } = window;
setDimensions((d) => {
if (width === d.width && height === d.height) {
return d;
}
return { width, height };
});
};
// We might have missed an update before the listener was added
// So make sure to update the dimensions
onChange({ window: Dimensions.get('window') });
Dimensions.addEventListener('change', onChange);
return () => Dimensions.addEventListener('change', onChange);
}, []);
return dimensions;
}

View File

@@ -1,11 +1,9 @@
import * as React from 'react';
import {
View,
Dimensions,
StyleSheet,
I18nManager,
Platform,
ScaledSize,
BackHandler,
NativeEventSubscription,
} from 'react-native';
@@ -25,6 +23,7 @@ import DrawerContent from './DrawerContent';
import Drawer from './Drawer';
import DrawerOpenContext from '../utils/DrawerOpenContext';
import DrawerPositionContext from '../utils/DrawerPositionContext';
import useWindowDimensions from '../utils/useWindowDimensions';
import type {
DrawerDescriptorMap,
DrawerNavigationConfig,
@@ -86,9 +85,7 @@ export default function DrawerView({
sceneContainerStyle,
}: Props) {
const [loaded, setLoaded] = React.useState([state.index]);
const [dimensions, setDimensions] = React.useState(() =>
Dimensions.get('window')
);
const dimensions = useWindowDimensions();
const { colors } = useTheme();
@@ -133,16 +130,6 @@ export default function DrawerView({
return () => subscription?.remove();
}, [handleDrawerClose, isDrawerOpen, navigation, state.key]);
React.useEffect(() => {
const updateDimensions = ({ window }: { window: ScaledSize }) => {
setDimensions(window);
};
Dimensions.addEventListener('change', updateDimensions);
return () => Dimensions.removeEventListener('change', updateDimensions);
}, []);
if (!loaded.includes(state.index)) {
setLoaded([...loaded, state.index]);
}