useKeyboardState
useKeyboardState
is a hook which gives an access to current keyboard state. This hook combines data from KeyboardController.state()
and KeyboardController.isVisible()
methods and makes it reactive (i. e. triggers a re-render when keyboard state/visibility has changed).
Donβt use state
from useKeyboardState
inside event handlers. It will cause unnecessary re-renders. See common pitfalls section for more details and alternatives.
Make sure that if you want to animate something based on keyboard presence then you've seen optimize animation section.
useKeyboardState
allows you to pass a selector function to pick only the necessary part of the keyboard state data. This is a powerful technique to prevent unnecessary re-renders of your component when only a specific property of the keyboard state changes.
const appearance = useKeyboardState((state) => state.appearance);
In this example, your component will only re-render when the appearance
property of the KeyboardState
changes, rather than for any change in the entire state object.
Data structureβ
The KeyboardState
is represented by following structure:
type KeyboardState = {
isVisible: boolean;
height: number;
duration: number; // duration of the animation
timestamp: number; // timestamp of the event from native thread
target: number; // tag of the focused `TextInput`
type: string; // `keyboardType` property from focused `TextInput`
appearance: string; // `keyboardAppearance` property from focused `TextInput`
};
π« Common Pitfallsβ
β οΈ Avoid Unnecessary Re-rendersβ
If you need to access the keyboard state
in callbacks or event handlers then consider to use KeyboardController.state() or KeyboardController.isVisible() methods instead. This allows you to retrieve values as needed without triggering unnecessary re-renders.
// use KeyboardController.isVisible()
<Button
onPress={() => {
// β
read value on demand
if (KeyboardController.isVisible()) {
// ...
}
}}
>
Go to Next Page
</Button>
const { isVisible } = useKeyboardState();
<Button
onPress={() => {
// β don't consume state from hook
if (isVisible) {
// ...
}
}}
>
Go to next Page
</Button>;
β‘οΈ Optimize Animations with Native Threadsβ
Don't use useKeyboardState
for controlling styles, because:
- applying it directly to styles can lead to choppy animations;
- it changes its values frequently making excessive re-renders on each keyboard state change.
If you need to change styles then you can use "animated" hooks such as useKeyboardAnimation, useReanimatedKeyboardAnimation or even useKeyboardHandler to offload animation to a native thread and free up resources for JS thread.
const { height } = useKeyboardAnimation();
<Animated.View
style={{
width: "100%",
transform: [{ translateY: height }],
}}
>
...
</Animated.View>;
const { height } = useKeyboardState();
<View
style={{
width: "100%",
transform: [{ translateY: height }],
}}
>
...
</View>;
Exampleβ
import { View, Text, StyleSheet } from "react-native";
import { useKeyboardState } from "react-native-keyboard-controller";
const ShowcaseComponent = () => {
const isVisible = useKeyboardState((state) => state.isVisible);
return isVisible ? (
<View style={styles.highlighted}>
<Text>Address form</Text>
</View>
) : null;
};
const styles = StyleSheet.create({
highlighted: {
borderColor: "#0070D8",
},
});
Also have a look on example app for more comprehensive usage.