Skip to content

Commit 45c23bf

Browse files
adamgrzybowskiShevO27
authored andcommitted
Don't use setState for disabled KeyboardAvoidingView to avoid re-renders (facebook#38074)
Summary: There are two reasons to apply these changes: - We don't need to re-render the `KeyboardAvoidingView` if it is disabled. It may be especially useful in combination with [react-navigation](https://reactnavigation.org/) where we could disable `KeyboardAvoidingView` for screens that are not focused - They fix the problem with the `KeyboardAvoidingView` wrapped inside the [react-freeze](https://github.com/software-mansion/react-freeze) component. Similarly, as above, it is useful when we want to freeze screens that are not visible for the user. ## Changelog: [GENERAL] [CHANGED] Don't use setState for disabled KeyboardAvoidingView to avoid re-renders <!-- Help reviewers and the release process by writing your own changelog entry. Pick one each for the category and type tags: [ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message For more details, see: https://reactnative.dev/contributing/changelogs-in-pull-requests Pull Request resolved: facebook#38074 Test Plan: - Check if the KeyboardAvoidingView works as expected. Reviewed By: sammy-SC Differential Revision: D49148391 Pulled By: blakef fbshipit-source-id: c4b7bde696d2249cbf4ad12c77058183b632464d
1 parent 82bf41b commit 45c23bf

File tree

1 file changed

+23
-4
lines changed

1 file changed

+23
-4
lines changed

packages/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ class KeyboardAvoidingView extends React.Component<Props, State> {
6565
_subscriptions: Array<EventSubscription> = [];
6666
viewRef: {current: React.ElementRef<typeof View> | null, ...};
6767
_initialFrameHeight: number = 0;
68+
_bottom: number = 0;
6869

6970
constructor(props: Props) {
7071
super(props);
@@ -129,20 +130,32 @@ class KeyboardAvoidingView extends React.Component<Props, State> {
129130
}
130131
};
131132

133+
// Avoid unnecessary renders if the KeyboardAvoidingView is disabled.
134+
_setBottom = (value: number) => {
135+
const enabled = this.props.enabled ?? true;
136+
this._bottom = value;
137+
if (enabled) {
138+
this.setState({bottom: value});
139+
}
140+
};
141+
132142
_updateBottomIfNecessary = async () => {
133143
if (this._keyboardEvent == null) {
134-
this.setState({bottom: 0});
144+
this._setBottom(0);
135145
return;
136146
}
137147

138148
const {duration, easing, endCoordinates} = this._keyboardEvent;
139149
const height = await this._relativeKeyboardHeight(endCoordinates);
140150

141-
if (this.state.bottom === height) {
151+
if (this._bottom === height) {
142152
return;
143153
}
144154

145-
if (duration && easing) {
155+
this._setBottom(height);
156+
157+
const enabled = this.props.enabled ?? true;
158+
if (enabled && duration && easing) {
146159
LayoutAnimation.configureNext({
147160
// We have to pass the duration equal to minimal accepted duration defined here: RCTLayoutAnimation.m
148161
duration: duration > 10 ? duration : 10,
@@ -152,9 +165,15 @@ class KeyboardAvoidingView extends React.Component<Props, State> {
152165
},
153166
});
154167
}
155-
this.setState({bottom: height});
156168
};
157169

170+
componentDidUpdate(_: Props, prevState: State): void {
171+
const enabled = this.props.enabled ?? true;
172+
if (enabled && this._bottom !== prevState.bottom) {
173+
this.setState({bottom: this._bottom});
174+
}
175+
}
176+
158177
componentDidMount(): void {
159178
if (Platform.OS === 'ios') {
160179
this._subscriptions = [

0 commit comments

Comments
 (0)