Add dismiss helper, made possible by also adding carefullyGetParent (#3669)

* Add dismiss action, made possible by getParentState

* Add dismiss to flow interface

* Don't dispatch an action on dismiss helper if no parent state

* carefullyGetParent instead of getParentState
This commit is contained in:
Brent Vatne 2018-03-12 16:01:29 -07:00 committed by GitHub
parent 052d22804c
commit 9a6e0bbd98
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 48 additions and 2 deletions

View File

@ -49,7 +49,8 @@ class MyNavScreen extends React.Component<MyNavScreenProps> {
/>
<Button onPress={() => navigation.popToTop()} title="Pop to top" />
<Button onPress={() => navigation.pop()} title="Pop" />
<Button onPress={() => navigation.goBack(null)} title="Go back" />
<Button onPress={() => navigation.goBack()} title="Go back" />
<Button onPress={() => navigation.dismiss()} title="Dismiss" />
<StatusBar barStyle="default" />
</SafeAreaView>
);

View File

@ -486,6 +486,7 @@ declare module 'react-navigation' {
+state: S,
dispatch: NavigationDispatch,
goBack: (routeKey?: ?string) => boolean,
dismiss: () => boolean,
navigate: (
routeName: string,
params?: NavigationParams,

View File

@ -6,6 +6,32 @@ const dummyEventSubscriber = (name: string, handler: (*) => void) => ({
});
describe('addNavigationHelpers', () => {
it('handles dismiss action', () => {
const mockedDispatch = jest
.fn(() => false)
.mockImplementationOnce(() => true);
const child = { key: 'A', routeName: 'Home' };
expect(
addNavigationHelpers({
state: child,
dispatch: mockedDispatch,
addListener: dummyEventSubscriber,
carefullyGetParent: () => ({
state: {
key: 'P',
routeName: 'Parent',
routes: [child],
},
}),
}).dismiss()
).toEqual(true);
expect(mockedDispatch).toBeCalledWith({
type: NavigationActions.BACK,
key: 'P',
});
expect(mockedDispatch.mock.calls.length).toBe(1);
});
it('handles Back action', () => {
const mockedDispatch = jest
.fn(() => false)

View File

@ -2,10 +2,10 @@
import NavigationActions from './NavigationActions';
import invariant from './utils/invariant';
export default function(navigation) {
return {
...navigation,
// Go back from the given key, default to active key
goBack: key => {
let actualizedKey = key;
if (key === undefined && navigation.state.key) {
@ -19,6 +19,18 @@ export default function(navigation) {
NavigationActions.back({ key: actualizedKey })
);
},
// Go back from the parent key. If this is a nested stack, the entire
// stack will be dismissed.
dismiss: () => {
let parent = navigation.carefullyGetParent();
if (parent && parent.state) {
return navigation.dispatch(
NavigationActions.back({ key: parent.state.key })
);
} else {
return false;
}
},
navigate: (navigateTo, params, action) => {
if (typeof navigateTo === 'string') {
return navigation.dispatch(

View File

@ -32,6 +32,10 @@ function createNavigator(NavigatorView, router, navigationConfig) {
return route === focusedRoute;
};
_carefullyGetParent = () => {
return this.props.navigation;
};
render() {
const { navigation, screenProps } = this.props;
const { dispatch, state, addListener } = navigation;
@ -52,9 +56,11 @@ function createNavigator(NavigatorView, router, navigationConfig) {
const childNavigation = addNavigationHelpers({
dispatch,
state: route,
carefullyGetParent: this._carefullyGetParent,
addListener: this.childEventSubscribers[route.key].addListener,
isFocused: () => this._isRouteFocused(route),
});
const options = router.getScreenOptions(childNavigation, screenProps);
descriptors[route.key] = {
key: route.key,