Skip to content

Commit b228940

Browse files
authored
Merge pull request Expensify#90522 from abzokhattab/revert/90358-reanimated-modal-react-compiler
Revert "Refactor ReanimatedModal/index.tsx to follow Rules of React and compile with React Compiler" (Expensify#90358)
2 parents 053707d + 606b3b8 commit b228940

1 file changed

Lines changed: 93 additions & 63 deletions

File tree

  • src/components/Modal/ReanimatedModal

src/components/Modal/ReanimatedModal/index.tsx

Lines changed: 93 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import noop from 'lodash/noop';
2-
import React, {useEffect, useEffectEvent, useRef, useState} from 'react';
2+
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
33
import type {NativeEventSubscription, ViewStyle} from 'react-native';
44
// eslint-disable-next-line no-restricted-imports
55
import {BackHandler, InteractionManager, Modal, StyleSheet, View} from 'react-native';
@@ -55,64 +55,37 @@ function ReanimatedModal({
5555
shouldReturnFocus,
5656
...props
5757
}: ReanimatedModalProps) {
58+
const [isVisibleState, setIsVisibleState] = useState(isVisible);
5859
const [isContainerOpen, setIsContainerOpen] = useState(false);
60+
const [isTransitioning, setIsTransitioning] = useState(false);
5961
const {windowWidth, windowHeight} = useWindowDimensions();
60-
const styles = useThemeStyles();
6162

6263
const backHandlerListener = useRef<NativeEventSubscription | null>(null);
6364
const handleRef = useRef<number | undefined>(undefined);
6465
const transitionHandleRef = useRef<TransitionHandle | null>(null);
6566

66-
const isTransitioning = isVisible !== isContainerOpen;
67-
const backdropStyle: ViewStyle = {width: windowWidth, height: windowHeight, backgroundColor: backdropColor};
68-
const modalStyle = {zIndex: StyleSheet.flatten(style)?.zIndex};
67+
const styles = useThemeStyles();
6968

70-
const onBackButtonPressHandler = () => {
69+
const onBackButtonPressHandler = useCallback(() => {
7170
if (shouldIgnoreBackHandlerDuringTransition && isTransitioning) {
7271
return false;
7372
}
74-
if (isVisible) {
73+
if (isVisibleState) {
7574
onBackButtonPress();
7675
return true;
7776
}
7877
return false;
79-
};
80-
81-
const handleEscape = (e: KeyboardEvent) => {
82-
if (e.key !== 'Escape' || onBackButtonPressHandler() !== true) {
83-
return;
84-
}
85-
e.stopImmediatePropagation();
86-
};
87-
88-
const clearTransitionHandles = () => {
89-
if (handleRef.current) {
90-
InteractionManager.clearInteractionHandle(handleRef.current);
91-
handleRef.current = undefined;
92-
}
93-
if (transitionHandleRef.current) {
94-
TransitionTracker.endTransition(transitionHandleRef.current);
95-
transitionHandleRef.current = null;
96-
}
97-
};
98-
99-
const onOpenCallBack = () => {
100-
setIsContainerOpen(true);
101-
clearTransitionHandles();
102-
onModalShow();
103-
};
104-
105-
const onCloseCallBack = () => {
106-
setIsContainerOpen(false);
107-
clearTransitionHandles();
78+
}, [isVisibleState, onBackButtonPress, isTransitioning, shouldIgnoreBackHandlerDuringTransition]);
10879

109-
// Because on Android, the Modal's onDismiss callback does not work reliably. There's a reported issue at:
110-
// https://stackoverflow.com/questions/58937956/react-native-modal-ondismiss-not-invoked
111-
// Therefore, we manually call onModalHide() here for Android.
112-
if (getPlatform() === CONST.PLATFORM.ANDROID) {
113-
onModalHide();
114-
}
115-
};
80+
const handleEscape = useCallback(
81+
(e: KeyboardEvent) => {
82+
if (e.key !== 'Escape' || onBackButtonPressHandler() !== true) {
83+
return;
84+
}
85+
e.stopImmediatePropagation();
86+
},
87+
[onBackButtonPressHandler],
88+
);
11689

11790
useEffect(() => {
11891
if (getPlatform() === CONST.PLATFORM.WEB) {
@@ -130,29 +103,86 @@ function ReanimatedModal({
130103
};
131104
}, [handleEscape, onBackButtonPressHandler]);
132105

106+
useEffect(
107+
() => () => {
108+
if (handleRef.current) {
109+
// eslint-disable-next-line @typescript-eslint/no-deprecated
110+
InteractionManager.clearInteractionHandle(handleRef.current);
111+
}
112+
if (transitionHandleRef.current) {
113+
TransitionTracker.endTransition(transitionHandleRef.current);
114+
transitionHandleRef.current = null;
115+
}
116+
117+
setIsVisibleState(false);
118+
setIsContainerOpen(false);
119+
},
120+
121+
[],
122+
);
123+
133124
useEffect(() => {
134-
if (isTransitioning) {
125+
if (isVisible && !isContainerOpen && !isTransitioning) {
126+
// eslint-disable-next-line @typescript-eslint/no-deprecated
135127
handleRef.current = InteractionManager.createInteractionHandle();
136128
transitionHandleRef.current = TransitionTracker.startTransition();
137-
}
138-
139-
return () => {
140-
clearTransitionHandles();
141-
};
142-
}, [isTransitioning]);
143-
144-
const fireTransitionCallbacks = useEffectEvent(() => {
145-
if (isVisible && !isContainerOpen) {
146129
onModalWillShow();
147-
} else if (!isVisible && isContainerOpen) {
130+
131+
// eslint-disable-next-line react-hooks/set-state-in-effect
132+
setIsVisibleState(true);
133+
setIsTransitioning(true);
134+
} else if (!isVisible && isContainerOpen && !isTransitioning) {
135+
handleRef.current = InteractionManager.createInteractionHandle();
136+
transitionHandleRef.current = TransitionTracker.startTransition();
148137
onModalWillHide();
138+
149139
blurActiveElement();
140+
setIsVisibleState(false);
141+
setIsTransitioning(true);
150142
}
151-
});
143+
// eslint-disable-next-line react-hooks/exhaustive-deps
144+
}, [isVisible, isContainerOpen, isTransitioning]);
152145

153-
useEffect(() => {
154-
fireTransitionCallbacks();
155-
}, [isVisible, isContainerOpen]);
146+
const backdropStyle: ViewStyle = useMemo(() => {
147+
return {width: windowWidth, height: windowHeight, backgroundColor: backdropColor};
148+
}, [windowWidth, windowHeight, backdropColor]);
149+
150+
const onOpenCallBack = useCallback(() => {
151+
setIsTransitioning(false);
152+
setIsContainerOpen(true);
153+
if (handleRef.current) {
154+
// eslint-disable-next-line @typescript-eslint/no-deprecated
155+
InteractionManager.clearInteractionHandle(handleRef.current);
156+
}
157+
if (transitionHandleRef.current) {
158+
TransitionTracker.endTransition(transitionHandleRef.current);
159+
transitionHandleRef.current = null;
160+
}
161+
onModalShow();
162+
}, [onModalShow]);
163+
164+
const onCloseCallBack = useCallback(() => {
165+
setIsTransitioning(false);
166+
setIsContainerOpen(false);
167+
if (handleRef.current) {
168+
InteractionManager.clearInteractionHandle(handleRef.current);
169+
}
170+
if (transitionHandleRef.current) {
171+
TransitionTracker.endTransition(transitionHandleRef.current);
172+
transitionHandleRef.current = null;
173+
}
174+
175+
// Because on Android, the Modal's onDismiss callback does not work reliably. There's a reported issue at:
176+
// https://stackoverflow.com/questions/58937956/react-native-modal-ondismiss-not-invoked
177+
// Therefore, we manually call onModalHide() here for Android.
178+
if (getPlatform() === CONST.PLATFORM.ANDROID) {
179+
onModalHide();
180+
}
181+
}, [onModalHide]);
182+
183+
const modalStyle = useMemo(() => {
184+
return {zIndex: StyleSheet.flatten(style)?.zIndex};
185+
}, [style]);
156186

157187
const containerView = (
158188
<Container
@@ -186,7 +216,7 @@ function ReanimatedModal({
186216
/>
187217
);
188218

189-
if (!coverScreen && isVisible) {
219+
if (!coverScreen && isVisibleState) {
190220
return (
191221
<View
192222
pointerEvents="box-none"
@@ -197,8 +227,8 @@ function ReanimatedModal({
197227
</View>
198228
);
199229
}
200-
const isBackdropMounted = isVisible || (isTransitioning && getPlatform() === CONST.PLATFORM.WEB);
201-
const modalVisibility = isVisible || isTransitioning;
230+
const isBackdropMounted = isVisibleState || ((isTransitioning || isContainerOpen !== isVisibleState) && getPlatform() === CONST.PLATFORM.WEB);
231+
const modalVisibility = isVisibleState || isTransitioning || isContainerOpen !== isVisibleState;
202232
return (
203233
<LayoutAnimationConfig skipExiting={getPlatform() !== CONST.PLATFORM.WEB}>
204234
<Modal
@@ -225,7 +255,7 @@ function ReanimatedModal({
225255
pointerEvents="box-none"
226256
style={[style, {margin: 0}]}
227257
>
228-
{isVisible && containerView}
258+
{isVisibleState && containerView}
229259
</KeyboardAvoidingView>
230260
) : (
231261
<FocusTrapForModal
@@ -234,7 +264,7 @@ function ReanimatedModal({
234264
shouldReturnFocus={shouldReturnFocus ?? !shouldEnableNewFocusManagement}
235265
shouldPreventScroll={shouldPreventScrollOnFocus}
236266
>
237-
{isVisible && containerView}
267+
{isVisibleState && containerView}
238268
</FocusTrapForModal>
239269
)}
240270
</Modal>

0 commit comments

Comments
 (0)