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.popToTop()} title="Pop to top" />
<Button onPress={() => navigation.pop()} title="Pop" /> <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" /> <StatusBar barStyle="default" />
</SafeAreaView> </SafeAreaView>
); );

View File

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

View File

@ -6,6 +6,32 @@ const dummyEventSubscriber = (name: string, handler: (*) => void) => ({
}); });
describe('addNavigationHelpers', () => { 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', () => { it('handles Back action', () => {
const mockedDispatch = jest const mockedDispatch = jest
.fn(() => false) .fn(() => false)

View File

@ -2,10 +2,10 @@
import NavigationActions from './NavigationActions'; import NavigationActions from './NavigationActions';
import invariant from './utils/invariant'; import invariant from './utils/invariant';
export default function(navigation) { export default function(navigation) {
return { return {
...navigation, ...navigation,
// Go back from the given key, default to active key
goBack: key => { goBack: key => {
let actualizedKey = key; let actualizedKey = key;
if (key === undefined && navigation.state.key) { if (key === undefined && navigation.state.key) {
@ -19,6 +19,18 @@ export default function(navigation) {
NavigationActions.back({ key: actualizedKey }) 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) => { navigate: (navigateTo, params, action) => {
if (typeof navigateTo === 'string') { if (typeof navigateTo === 'string') {
return navigation.dispatch( return navigation.dispatch(

View File

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