Skip to content

Commit

Permalink
ComponentDidDisappear event Android fix (#7392)
Browse files Browse the repository at this point in the history
* Add Test to ensure events are sent accordingly

* disable toptabs test

Unsupported these days

* Post Event Emitter events on View Queue

To make sure that the view done its work with RN thread by initializing the component constructor and call mount, then it can have the events sent.

* Events are sent on View MessageQueue

No need for this, since the event emitter now posts such actions on ReactView messageQueue, hence, it will be synchronized with what happens on the view by the ReactNative.

* Don't send Disappear event when the view is disappeared

* no need to have on appeared

* add event logs to playground main components for debug

* Update TopTabsViewControllerTest.java
  • Loading branch information
swabbass authored Dec 8, 2021
1 parent c14724e commit bc483a6
Show file tree
Hide file tree
Showing 10 changed files with 87 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,18 +66,22 @@ public void destroy() {
}

public void sendComponentWillStart(ComponentType type) {
if (this.reactInstanceManager == null) return;
ReactContext currentReactContext = reactInstanceManager.getCurrentReactContext();
if (currentReactContext != null)
new EventEmitter(currentReactContext).emitComponentWillAppear(componentId, componentName, type);
this.post(()->{
if (this.reactInstanceManager == null) return;
ReactContext currentReactContext = reactInstanceManager.getCurrentReactContext();
if (currentReactContext != null)
new EventEmitter(currentReactContext).emitComponentWillAppear(componentId, componentName, type);
});
}

public void sendComponentStart(ComponentType type) {
if (this.reactInstanceManager == null) return;
ReactContext currentReactContext = reactInstanceManager.getCurrentReactContext();
if (currentReactContext != null) {
new EventEmitter(currentReactContext).emitComponentDidAppear(componentId, componentName, type);
}
this.post(()->{
if (this.reactInstanceManager == null) return;
ReactContext currentReactContext = reactInstanceManager.getCurrentReactContext();
if (currentReactContext != null) {
new EventEmitter(currentReactContext).emitComponentDidAppear(componentId, componentName, type);
}
});
}

public void sendComponentStop(ComponentType type) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ public void onViewDidAppear() {

@Override
public void onViewDisappear() {
if(lastVisibilityState == VisibilityState.Disappear)return;
lastVisibilityState = VisibilityState.Disappear;
if (view != null) view.sendComponentStop();
super.onViewDisappear();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,10 @@ public void onCancel() {
}

private void onShowModalEnd(ViewController<?> toAdd, @Nullable ViewController<?> toRemove, CommandListener listener) {
toAdd.addOnAppearedListener(()->{
toAdd.onViewDidAppear();
if (toRemove != null && toAdd.resolveCurrentOptions(defaultOptions).modal.presentationStyle != ModalPresentationStyle.OverCurrentContext) {
toRemove.detachView();
}
});
toAdd.onViewDidAppear();
if (toRemove != null && toAdd.resolveCurrentOptions(defaultOptions).modal.presentationStyle != ModalPresentationStyle.OverCurrentContext) {
toRemove.detachView();
}
listener.onSuccess(toAdd.getId());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,10 +190,8 @@ public void destroy() {
}

private void onPushAnimationComplete(ViewController<?> toAdd, ViewController<?> toRemove, CommandListener listener) {
toAdd.addOnAppearedListener(() -> {
toAdd.onViewDidAppear();
if (!peek().equals(toRemove)) getView().removeView(toRemove.getView());
});
toAdd.onViewDidAppear();
if (!peek().equals(toRemove)) getView().removeView(toRemove.getView());
listener.onSuccess(toAdd.getId());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,24 @@ public void lifecycleMethodsSentToComponentView() {
Mockito.verify(view, Mockito.times(1)).sendComponentStop();
}

@Test
public void shouldNotSendDidDisappearAboutDisappearedView() {
uut.ensureViewIsCreated();
uut.onViewDisappear();
Mockito.verify(view, Mockito.times(0)).sendComponentStart();
Mockito.verify(view, Mockito.times(0)).sendComponentStop();

uut.onViewWillAppear();
uut.onViewDidAppear();
uut.onViewDisappear();
Mockito.verify(view, Mockito.times(1)).sendComponentStart();
Mockito.verify(view, Mockito.times(1)).sendComponentStop();

uut.onViewDisappear();
Mockito.verify(view, Mockito.times(1)).sendComponentStart();
Mockito.verify(view, Mockito.times(1)).sendComponentStop();
}

@Test
public void onViewDidAppear_componentStartIsEmittedOnlyIfComponentIsNotAppeared() {
uut.ensureViewIsCreated();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,9 @@ public void beforeEach() {
}

@Test
public void showModal_DidAppearEventShouldWaitForReactViewToBeShown(){
public void showModal_DidAppearEventShouldBeCallled(){
CommandListener listener = spy(new CommandListenerAdapter());
uut.showModal(modal1, root, listener);
verify(modal1).addOnAppearedListener(any());
verify(listener).onSuccess(modal1.getId());
idleMainLooper();
verify(modal1).onViewDidAppear();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.reactnativenavigation.views.toptabs.TopTabsLayoutCreator;
import com.reactnativenavigation.views.toptabs.TopTabsViewPager;

import org.junit.Ignore;
import org.junit.Test;
import org.mockito.Mockito;

Expand Down Expand Up @@ -123,6 +124,7 @@ public void componentViewDestroyedOnDestroy() {
}

@Test
@Ignore("TopTabs not yet well supported")
public void lifecycleMethodsSentWhenSelectedTabChanges() {
stack.ensureViewIsCreated();
uut.ensureViewIsCreated();
Expand Down
8 changes: 8 additions & 0 deletions playground/src/screens/LayoutsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,16 @@ export default class LayoutsScreen extends NavigationComponent<NavigationCompone
componentDidAppear: false,
};
}
componentWillAppear() {
console.log('componentWillAppear:', this.props.componentId);
}

componentDidDisappear() {
console.log('componentDidDisappear:', this.props.componentId);
}

componentDidAppear() {
console.log('componentDidAppear:', this.props.componentId);
this.setState({ componentDidAppear: true });
}

Expand Down
21 changes: 19 additions & 2 deletions playground/src/screens/NavigationScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import React from 'react';
import { Platform } from 'react-native';
import { NavigationComponentProps, OptionsModalPresentationStyle } from 'react-native-navigation';
import {
NavigationComponent,
NavigationComponentProps,
OptionsModalPresentationStyle,
} from 'react-native-navigation';
import Root from '../components/Root';
import Button from '../components/Button';
import Navigation from './../services/Navigation';
Expand All @@ -22,7 +26,7 @@ const {

interface Props extends NavigationComponentProps {}

export default class NavigationScreen extends React.Component<Props> {
export default class NavigationScreen extends NavigationComponent<Props> {
static options() {
return {
topBar: {
Expand All @@ -37,7 +41,20 @@ export default class NavigationScreen extends React.Component<Props> {
},
};
}
constructor(props: Props) {
super(props);
Navigation.events().bindComponent(this);
}
componentWillAppear() {
console.log('componentWillAppear:', this.props.componentId);
}
componentDidDisappear() {
console.log('componentDidDisappear:', this.props.componentId);
}

componentDidAppear() {
console.log('componentDidAppear:', this.props.componentId);
}
render() {
return (
<Root componentId={this.props.componentId} testID={NAVIGATION_SCREEN}>
Expand Down
21 changes: 19 additions & 2 deletions playground/src/screens/OptionsScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { NavigationComponentProps } from 'react-native-navigation';
import { NavigationComponent, NavigationComponentProps } from 'react-native-navigation';
import Button from '../components/Button';
import Root from '../components/Root';
import Navigation from '../services/Navigation';
Expand All @@ -22,7 +22,7 @@ const {

interface Props extends NavigationComponentProps {}

export default class Options extends React.Component<Props> {
export default class Options extends NavigationComponent<Props> {
static options() {
return {
topBar: {
Expand All @@ -35,6 +35,23 @@ export default class Options extends React.Component<Props> {
};
}

constructor(props: Props) {
super(props);
Navigation.events().bindComponent(this);
}

componentWillAppear() {
console.log('componentWillAppear:', this.props.componentId);
}

componentDidDisappear() {
console.log('componentDidDisappear:', this.props.componentId);
}

componentDidAppear() {
console.log('componentDidAppear:', this.props.componentId);
}

state = {
isAndroidNavigationBarVisible: true,
};
Expand Down

0 comments on commit bc483a6

Please sign in to comment.