Skip to content

Commit 98f7078

Browse files
author
Mark de Vocht
committed
possible fix
1 parent 85819aa commit 98f7078

7 files changed

Lines changed: 129 additions & 1 deletion

File tree

ios/RNNStackController.mm

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,26 @@ - (void)mergeChildOptions:(RNNNavigationOptions *)options child:(UIViewControlle
4242

4343
- (UIViewController *)popViewControllerAnimated:(BOOL)animated {
4444
[self prepareForPop];
45-
return [super popViewControllerAnimated:animated];
45+
46+
UIViewController *topVC = self.topViewController;
47+
48+
if (animated && topVC.isViewLoaded && topVC.view.window) {
49+
UIView *snapshot = [topVC.view snapshotViewAfterScreenUpdates:NO];
50+
if (snapshot) {
51+
snapshot.frame = topVC.view.bounds;
52+
snapshot.autoresizingMask =
53+
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
54+
[topVC.view addSubview:snapshot];
55+
}
56+
}
57+
58+
if ([topVC isKindOfClass:[RNNComponentViewController class]]) {
59+
[[(RNNComponentViewController *)topVC reactView] componentDidDisappear];
60+
}
61+
62+
UIViewController *poppedVC = [super popViewControllerAnimated:animated];
63+
[poppedVC destroyReactView];
64+
return poppedVC;
4665
}
4766

4867
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item {

playground/e2e/Stack.test.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,15 @@ describe('Stack', () => {
183183
await expect(elementByLabel('pop promise resolved with: ChildId')).toBeVisible();
184184
});
185185

186+
it.e2e('pop and re-push same component should not have stale unmount', async () => {
187+
await elementById(TestIDs.PUSH_UNMOUNT_RACE_BTN).tap();
188+
await sleep(800);
189+
await expect(elementByLabel('loaded')).toBeVisible();
190+
await elementById(TestIDs.POP_AND_REPUSH_BTN).tap();
191+
await sleep(1000);
192+
await expect(elementByLabel('loaded')).toBeVisible();
193+
});
194+
186195
it('pop from root screen should do nothing', async () => {
187196
await elementById(TestIDs.POP_BTN).tap();
188197
await expect(elementById(TestIDs.STACK_SCREEN_HEADER)).toBeVisible();

playground/src/screens/Screens.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ const Screens = {
122122
},
123123
SystemUiOptions: SystemUiOptions,
124124
StatusBarFirstTab,
125+
UnmountRace: 'UnmountRace',
125126
KeyboardScreen: 'KeyboardScreen',
126127
TopBarBackground: 'TopBarBackground',
127128
Toast: 'Toast',

playground/src/screens/StackScreen.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const {
2121
SET_STACK_ROOT_WITH_ID_BTN,
2222
STACK_COMMANDS_BTN,
2323
SET_ROOT_NAVIGATION_TAB,
24+
PUSH_UNMOUNT_RACE_BTN,
2425
POP_BTN,
2526
} = testIDs;
2627

@@ -83,6 +84,11 @@ export default class StackScreen extends React.Component<NavigationProps> {
8384
testID={STACK_COMMANDS_BTN}
8485
onPress={this.pushStackCommands}
8586
/>
87+
<Button
88+
label="Push Unmount Race"
89+
testID={PUSH_UNMOUNT_RACE_BTN}
90+
onPress={this.pushUnmountRace}
91+
/>
8692
<Button label="Pop" testID={POP_BTN} onPress={this.pop} />
8793
</Root>
8894
);
@@ -166,5 +172,13 @@ export default class StackScreen extends React.Component<NavigationProps> {
166172

167173
pushStackCommands = () => Navigation.push(this, component(Screens.StackCommands));
168174

175+
pushUnmountRace = () =>
176+
Navigation.push(this, {
177+
component: {
178+
name: Screens.UnmountRace,
179+
passProps: { stackComponentId: this.props.componentId },
180+
},
181+
});
182+
169183
pop = () => Navigation.pop(this);
170184
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import React from 'react';
2+
import { Text, View, StyleSheet } from 'react-native';
3+
import { NavigationProps } from 'react-native-navigation';
4+
import Root from '../components/Root';
5+
import Button from '../components/Button';
6+
import Navigation from '../services/Navigation';
7+
import Screens from './Screens';
8+
import testIDs from '../testIDs';
9+
10+
let sharedData: string | null = null;
11+
12+
interface Props extends NavigationProps {
13+
stackComponentId?: string;
14+
}
15+
16+
export default class UnmountRaceScreen extends React.Component<Props, { data: string }> {
17+
static options() {
18+
return {
19+
topBar: {
20+
title: {
21+
text: 'Unmount Race',
22+
},
23+
},
24+
};
25+
}
26+
27+
state = { data: 'loading' };
28+
private checkTimer: ReturnType<typeof setTimeout> | null = null;
29+
30+
componentDidMount() {
31+
sharedData = 'loaded';
32+
this.checkTimer = setTimeout(() => {
33+
this.setState({ data: sharedData ?? 'stale_unmount' });
34+
}, 600);
35+
}
36+
37+
componentWillUnmount() {
38+
if (this.checkTimer) {
39+
clearTimeout(this.checkTimer);
40+
}
41+
sharedData = null;
42+
}
43+
44+
render() {
45+
return (
46+
<Root componentId={this.props.componentId}>
47+
<View style={styles.container}>
48+
<Text testID={testIDs.UNMOUNT_RACE_DATA} style={styles.text}>
49+
{this.state.data}
50+
</Text>
51+
</View>
52+
<Button
53+
label="Pop and Re-push"
54+
testID={testIDs.POP_AND_REPUSH_BTN}
55+
onPress={this.popAndRepush}
56+
/>
57+
<Button label="Pop" testID={testIDs.POP_BTN} onPress={this.pop} />
58+
</Root>
59+
);
60+
}
61+
62+
popAndRepush = () => {
63+
const stackId = this.props.stackComponentId;
64+
if (!stackId) return;
65+
Navigation.pop(this.props.componentId);
66+
Navigation.push(stackId, {
67+
component: {
68+
name: Screens.UnmountRace,
69+
passProps: { stackComponentId: stackId },
70+
},
71+
});
72+
};
73+
74+
pop = () => Navigation.pop(this);
75+
}
76+
77+
const styles = StyleSheet.create({
78+
container: { padding: 20, alignItems: 'center' },
79+
text: { fontSize: 24 },
80+
});

playground/src/screens/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ function registerScreens() {
117117
() => require('./SideMenuRightScreen').default
118118
);
119119
Navigation.registerComponent(Screens.Stack, () => require('./StackScreen').default);
120+
Navigation.registerComponent(Screens.UnmountRace, () => require('./UnmountRaceScreen').default);
120121
Navigation.registerComponent(Screens.SystemUiOptions, () => require('./SystemUiOptions').default);
121122
Navigation.registerComponent(
122123
Screens.StatusBarFirstTab,

playground/src/testIDs.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,10 @@ const testIDs = {
222222
TOGGLE_PLACEMENT_BTN: 'TOGGLE_PLACEMENT_BTN',
223223
MOUNTED_SCREENS_TEXT: 'MOUNTED_SCREENS_TEXT',
224224

225+
PUSH_UNMOUNT_RACE_BTN: 'PUSH_UNMOUNT_RACE_BTN',
226+
UNMOUNT_RACE_DATA: 'UNMOUNT_RACE_DATA',
227+
POP_AND_REPUSH_BTN: 'POP_AND_REPUSH_BTN',
228+
225229
GOTO_TOPBAR_TITLE_TEST: 'GOTO_TOPBAR_TITLE_TEST',
226230
TOPBAR_TITLE_TEXT: 'TOPBAR_TITLE_TEXT',
227231
TOPBAR_TITLE_AVATAR: 'TOPBAR_TITLE_AVATAR',

0 commit comments

Comments
 (0)