From 668ab65b47f714a3050924f7c0c9ecfb703186f3 Mon Sep 17 00:00:00 2001 From: Eric Vicenti Date: Thu, 1 Feb 2018 17:14:13 -0800 Subject: [PATCH] New StackRouter Push Action (#3401) --- src/NavigationActions.js | 17 ++++++++++++++++ src/addNavigationHelpers.js | 5 +++++ .../__snapshots__/StackNavigator-test.js.snap | 2 ++ src/routers/StackRouter.js | 19 ++++++++++++++---- src/routers/__tests__/StackRouter-test.js | 20 +++++++++++++++++++ .../__snapshots__/TabView-test.js.snap | 1 + 6 files changed, 60 insertions(+), 4 deletions(-) diff --git a/src/NavigationActions.js b/src/NavigationActions.js index a0618eb082..93e5373d6e 100644 --- a/src/NavigationActions.js +++ b/src/NavigationActions.js @@ -3,6 +3,7 @@ const INIT = 'Navigation/INIT'; const NAVIGATE = 'Navigation/NAVIGATE'; const POP = 'Navigation/POP'; const POP_TO_TOP = 'Navigation/POP_TO_TOP'; +const PUSH = 'Navigation/PUSH'; const RESET = 'Navigation/RESET'; const SET_PARAMS = 'Navigation/SET_PARAMS'; const URI = 'Navigation/URI'; @@ -56,6 +57,20 @@ const popToTop = createAction(POP_TO_TOP, payload => ({ immediate: payload && payload.immediate, })); +const push = createAction(PUSH, payload => { + const action = { + type: PUSH, + routeName: payload.routeName, + }; + if (payload.params) { + action.params = payload.params; + } + if (payload.action) { + action.action = payload.action; + } + return action; +}); + const reset = createAction(RESET, payload => ({ type: RESET, index: payload.index, @@ -138,6 +153,7 @@ export default { NAVIGATE, POP, POP_TO_TOP, + PUSH, RESET, SET_PARAMS, URI, @@ -149,6 +165,7 @@ export default { navigate, pop, popToTop, + push, reset, setParams, uri, diff --git a/src/addNavigationHelpers.js b/src/addNavigationHelpers.js index 12548527db..0841ce92a2 100644 --- a/src/addNavigationHelpers.js +++ b/src/addNavigationHelpers.js @@ -60,5 +60,10 @@ export default function(navigation) { const key = navigation.state.key; return navigation.dispatch(NavigationActions.setParams({ params, key })); }, + + push: (routeName, params, action) => + navigation.dispatch( + NavigationActions.push({ routeName, params, action }) + ), }; } diff --git a/src/navigators/__tests__/__snapshots__/StackNavigator-test.js.snap b/src/navigators/__tests__/__snapshots__/StackNavigator-test.js.snap index c586ba8e78..bc1023e8ce 100644 --- a/src/navigators/__tests__/__snapshots__/StackNavigator-test.js.snap +++ b/src/navigators/__tests__/__snapshots__/StackNavigator-test.js.snap @@ -99,6 +99,7 @@ exports[`StackNavigator applies correct values when headerRight is present 1`] = "navigate": [Function], "pop": [Function], "popToTop": [Function], + "push": [Function], "setParams": [Function], "state": Object { "index": 0, @@ -334,6 +335,7 @@ exports[`StackNavigator renders successfully 1`] = ` "navigate": [Function], "pop": [Function], "popToTop": [Function], + "push": [Function], "setParams": [Function], "state": Object { "index": 0, diff --git a/src/routers/StackRouter.js b/src/routers/StackRouter.js index e7fa8a12fe..b9b72396a5 100644 --- a/src/routers/StackRouter.js +++ b/src/routers/StackRouter.js @@ -17,6 +17,13 @@ function isEmpty(obj) { return true; } +function behavesLikePushAction(action) { + return ( + action.type === NavigationActions.NAVIGATE || + action.type === NavigationActions.PUSH + ); +} + export default (routeConfigs, stackConfig = {}) => { // Fail fast on invalid route definitions validateRouteConfigMap(routeConfigs); @@ -96,7 +103,7 @@ export default (routeConfigs, stackConfig = {}) => { if (!state) { let route = {}; if ( - action.type === NavigationActions.NAVIGATE && + behavesLikePushAction(action) && childRouters[action.routeName] !== undefined ) { return { @@ -178,13 +185,17 @@ export default (routeConfigs, stackConfig = {}) => { // Handle explicit push navigation action. Make sure this happens after children have had a chance to handle the action if ( - action.type === NavigationActions.NAVIGATE && + behavesLikePushAction(action) && childRouters[action.routeName] !== undefined ) { const childRouter = childRouters[action.routeName]; let route; - // The key may be provided for pushing, or to navigate back to the key + invariant( + action.type !== NavigationActions.PUSH || action.key == null, + 'StackRouter does not support key on the push action' + ); + // With the navigate action, the key may be provided for pushing, or to navigate back to the key if (action.key) { const lastRouteIndex = state.routes.findIndex( r => r.key === action.key @@ -252,7 +263,7 @@ export default (routeConfigs, stackConfig = {}) => { } // Handle navigation to other child routers that are not yet pushed - if (action.type === NavigationActions.NAVIGATE) { + if (behavesLikePushAction(action)) { const childRouterNames = Object.keys(childRouters); for (let i = 0; i < childRouterNames.length; i++) { const childRouterName = childRouterNames[i]; diff --git a/src/routers/__tests__/StackRouter-test.js b/src/routers/__tests__/StackRouter-test.js index ce0676ea5b..3e29723b2f 100644 --- a/src/routers/__tests__/StackRouter-test.js +++ b/src/routers/__tests__/StackRouter-test.js @@ -441,6 +441,26 @@ describe('StackRouter', () => { expect(pushedTwiceState.routes[1].routeName).toEqual('bar'); }); + test('Push behaves like navigate, except for key', () => { + const TestRouter = StackRouter({ + foo: { screen: () =>
}, + bar: { screen: () =>
}, + }); + const initState = TestRouter.getStateForAction(NavigationActions.init()); + const pushedState = TestRouter.getStateForAction( + NavigationActions.push({ routeName: 'bar' }), + initState + ); + expect(pushedState.index).toEqual(1); + expect(pushedState.routes[1].routeName).toEqual('bar'); + expect(() => { + TestRouter.getStateForAction( + { type: NavigationActions.PUSH, routeName: 'bar', key: 'a' }, + pushedState + ); + }).toThrow(); + }); + test('Handle basic stack logic for plain components', () => { const FooScreen = () =>
; const BarScreen = () =>
; diff --git a/src/views/__tests__/__snapshots__/TabView-test.js.snap b/src/views/__tests__/__snapshots__/TabView-test.js.snap index 046827474e..3f75ccaab9 100644 --- a/src/views/__tests__/__snapshots__/TabView-test.js.snap +++ b/src/views/__tests__/__snapshots__/TabView-test.js.snap @@ -226,6 +226,7 @@ exports[`TabBarBottom renders successfully 1`] = ` "navigate": [Function], "pop": [Function], "popToTop": [Function], + "push": [Function], "setParams": [Function], "state": Object { "key": "s1",