From 15caee76f36c72647fc6d0ca84d959a516deea60 Mon Sep 17 00:00:00 2001 From: James Isaac Date: Mon, 20 Feb 2017 21:59:46 +0000 Subject: [PATCH] Merge action params into navigator's child screens (#306) --- src/TypeDefinition.js | 1 + src/routers/StackRouter.js | 8 +++- src/routers/TabRouter.js | 19 ++++++++- src/routers/__tests__/StackRouter-test.js | 50 +++++++++++++++++++++++ src/routers/__tests__/TabRouter-test.js | 36 ++++++++++++++++ 5 files changed, 112 insertions(+), 2 deletions(-) diff --git a/src/TypeDefinition.js b/src/TypeDefinition.js index 4abab90..97c94d9 100644 --- a/src/TypeDefinition.js +++ b/src/TypeDefinition.js @@ -247,6 +247,7 @@ export type NavigationSetParamsAction = { export type NavigationInitAction = { type: 'Navigation/INIT', + params?: NavigationParams, }; export type NavigationResetAction = { diff --git a/src/routers/StackRouter.js b/src/routers/StackRouter.js index 7a10387..d724bb1 100644 --- a/src/routers/StackRouter.js +++ b/src/routers/StackRouter.js @@ -113,10 +113,15 @@ export default ( params: initialRouteParams, })); } + const params = (route.params || action.params) && { + ...(route.params || {}), + ...(action.params || {}), + }; route = { ...route, routeName: initialRouteName, key: 'Init', + ...(params ? { params } : {}), }; state = { index: 0, @@ -139,9 +144,10 @@ export default ( const childRouter = childRouters[action.routeName]; let route; if (childRouter) { + const childAction = action.action || NavigationActions.init({ params: action.params }); route = { ...action, - ...childRouter.getStateForAction(action.action || NavigationActions.init()), + ...childRouter.getStateForAction(childAction), key: _getUuid(), routeName: action.routeName, }; diff --git a/src/routers/TabRouter.js b/src/routers/TabRouter.js index 81db7fb..4a7d0f0 100644 --- a/src/routers/TabRouter.js +++ b/src/routers/TabRouter.js @@ -60,8 +60,11 @@ export default ( const routes = order.map((routeName: string) => { const tabRouter = tabRouters[routeName]; if (tabRouter) { + const childAction = action.action || NavigationActions.init({ + ...(action.params ? { params: action.params } : {}), + }); return { - ...tabRouter.getStateForAction(action.action || NavigationActions.init()), + ...tabRouter.getStateForAction(childAction), key: routeName, routeName, }; @@ -78,6 +81,20 @@ export default ( // console.log(`${order.join('-')}: Initial state`, {state}); } + if (action.type === NavigationActions.INIT) { + // Merge any params from the action into all the child routes + const { params } = action; + if (params) { + state.routes = state.routes.map(route => ({ + ...route, + params: { + ...route.params, + ...params, + } + })); + } + } + // Let the current tab handle it const activeTabLastState = state.routes[state.index]; const activeTabRouter = tabRouters[order[state.index]]; diff --git a/src/routers/__tests__/StackRouter-test.js b/src/routers/__tests__/StackRouter-test.js index 5d303ee..fbdc04e 100644 --- a/src/routers/__tests__/StackRouter-test.js +++ b/src/routers/__tests__/StackRouter-test.js @@ -468,6 +468,56 @@ describe('StackRouter', () => { expect(state2 && state2.routes[0].routes[0].routeName).toEqual('baz'); }); + test('Handles the navigate action with params and nested StackRouter', () => { + const ChildNavigator = () =>
; + ChildNavigator.router = StackRouter({ Baz: { screen: () =>
} }); + + const router = StackRouter({ + Foo: { screen: () =>
, }, + Bar: { screen: ChildNavigator, }, + }); + const state = router.getStateForAction({ type: NavigationActions.INIT }); + const state2 = router.getStateForAction({ type: NavigationActions.NAVIGATE, routeName: 'Bar', params: { foo: '42' } }, state); + expect(state2 && state2.routes[1].params).toEqual({ foo: '42' }); + /* $FlowFixMe */ + expect(state2 && state2.routes[1].routes).toEqual([ + { + key: 'Init', + routeName: 'Baz', + params: { foo: '42' }, + }, + ]); + }); + + test('Handles the navigate action with params and nested TabRouter', () => { + const ChildNavigator = () =>
; + ChildNavigator.router = TabRouter({ + Baz: { screen: () =>
}, + Boo: { screen: () =>
}, + }); + + const router = StackRouter({ + Foo: { screen: () =>
, }, + Bar: { screen: ChildNavigator, }, + }); + const state = router.getStateForAction({ type: NavigationActions.INIT }); + const state2 = router.getStateForAction({ type: NavigationActions.NAVIGATE, routeName: 'Bar', params: { foo: '42' } }, state); + expect(state2 && state2.routes[1].params).toEqual({ foo: '42' }); + /* $FlowFixMe */ + expect(state2 && state2.routes[1].routes).toEqual([ + { + key: 'Baz', + routeName: 'Baz', + params: { foo: '42' }, + }, + { + key: 'Boo', + routeName: 'Boo', + params: { foo: '42' }, + }, + ]); + }); + test('Handles empty URIs', () => { const router = StackRouter({ Foo: { diff --git a/src/routers/__tests__/TabRouter-test.js b/src/routers/__tests__/TabRouter-test.js index 7dd5c78..389b19e 100644 --- a/src/routers/__tests__/TabRouter-test.js +++ b/src/routers/__tests__/TabRouter-test.js @@ -139,6 +139,42 @@ describe('TabRouter', () => { }); }); + test('Handles passing params to nested tabs', () => { + const ChildTabNavigator = () =>
; + ChildTabNavigator.router = TabRouter({ Boo: BareLeafRouteConfig, Bar: BareLeafRouteConfig }); + const router = TabRouter({ Foo: BareLeafRouteConfig, Baz: { screen: ChildTabNavigator } }); + const navAction = { type: NavigationActions.NAVIGATE, routeName: 'Baz', params: { foo: '42', bar: '43' } }; + let state = router.getStateForAction(navAction); + expect(state).toEqual({ + index: 1, + routes: [ + { key: 'Foo', routeName: 'Foo' }, + { + index: 0, + key: 'Baz', + routeName: 'Baz', + routes: [ + { key: 'Boo', routeName: 'Boo', params: { foo: '42', bar: '43' } }, + { key: 'Bar', routeName: 'Bar', params: { foo: '42', bar: '43' } }, + ], + }, + ], + }); + + // Ensure that navigating back and forth doesn't overwrite + state = router.getStateForAction({ type: NavigationActions.NAVIGATE, routeName: 'Bar' }, state); + state = router.getStateForAction({ type: NavigationActions.NAVIGATE, routeName: 'Boo' }, state); + expect(state && state.routes[1]).toEqual({ + index: 0, + key: 'Baz', + routeName: 'Baz', + routes: [ + { key: 'Boo', routeName: 'Boo', params: { foo: '42', bar: '43' } }, + { key: 'Bar', routeName: 'Bar', params: { foo: '42', bar: '43' } }, + ], + }); + }); + test('Handles initial deep linking into nested tabs', () => { const ChildTabNavigator = () =>
; ChildTabNavigator.router = TabRouter({ Foo: BareLeafRouteConfig, Bar: BareLeafRouteConfig });