diff --git a/CHANGELOG.md b/CHANGELOG.md index 514ad2a88e..0073694652 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Changed +- StackNavigator.replace method no longer requires a key param. If the key is left undefined, the last screen in the stack will be replaced. ## [2.6.2] - [2018-07-06](https://github.com/react-navigation/react-navigation/releases/tag/2.6.2) ### Changed diff --git a/src/routers/StackRouter.js b/src/routers/StackRouter.js index 93fac47a7d..d47c6908b7 100644 --- a/src/routers/StackRouter.js +++ b/src/routers/StackRouter.js @@ -397,7 +397,15 @@ export default (routeConfigs, stackConfig = {}) => { // Handle replace action if (action.type === StackActions.REPLACE) { - const routeIndex = state.routes.findIndex(r => r.key === action.key); + let routeIndex; + + // If the key param is undefined, set the index to the last route in the stack + if (action.key === undefined && state.routes.length) { + routeIndex = state.routes.length - 1; + } else { + routeIndex = state.routes.findIndex(r => r.key === action.key); + } + // Only replace if the key matches one of our routes if (routeIndex !== -1) { const childRouter = childRouters[action.routeName]; diff --git a/src/routers/__tests__/StackRouter-test.js b/src/routers/__tests__/StackRouter-test.js index 03d1c053e7..8d5248b0cc 100644 --- a/src/routers/__tests__/StackRouter-test.js +++ b/src/routers/__tests__/StackRouter-test.js @@ -970,6 +970,77 @@ describe('StackRouter', () => { expect(replacedState2.routes[0].routeName).toEqual('bar'); }); + test('Replace action returns most recent route if no key is provided', () => { + const GrandChildNavigator = () =>
; + GrandChildNavigator.router = StackRouter({ + Quux: { screen: () =>
}, + Corge: { screen: () =>
}, + Grault: { screen: () =>
}, + }); + + const ChildNavigator = () =>
; + ChildNavigator.router = StackRouter({ + Baz: { screen: () =>
}, + Woo: { screen: () =>
}, + Qux: { screen: GrandChildNavigator }, + }); + + const router = StackRouter({ + Foo: { screen: () =>
}, + Bar: { screen: ChildNavigator }, + }); + + const state = router.getStateForAction({ type: NavigationActions.INIT }); + const state2 = router.getStateForAction( + { + type: NavigationActions.NAVIGATE, + routeName: 'Bar', + }, + state + ); + const state3 = router.getStateForAction( + { + type: NavigationActions.NAVIGATE, + routeName: 'Qux', + }, + state2 + ); + const state4 = router.getStateForAction( + { + type: NavigationActions.NAVIGATE, + routeName: 'Corge', + }, + state3 + ); + const state5 = router.getStateForAction( + { + type: NavigationActions.NAVIGATE, + routeName: 'Grault', + }, + state4 + ); + + const replacedState = router.getStateForAction( + StackActions.replace({ + routeName: 'Woo', + params: { meaning: 42 }, + }), + state5 + ); + + const originalCurrentScreen = state5.routes[1].routes[1].routes[2]; + const replacedCurrentScreen = replacedState.routes[1].routes[1].routes[2]; + + expect(replacedState.routes[1].routes[1].index).toEqual(2); + expect(replacedState.routes[1].routes[1].routes.length).toEqual(3); + expect(replacedCurrentScreen.key).not.toEqual(originalCurrentScreen.key); + expect(replacedCurrentScreen.routeName).not.toEqual( + originalCurrentScreen.routeName + ); + expect(replacedCurrentScreen.routeName).toEqual('Woo'); + expect(replacedCurrentScreen.params.meaning).toEqual(42); + }); + test('Handles push transition logic with completion action', () => { const FooScreen = () =>
; const BarScreen = () =>
;