Skip to content
This repository was archived by the owner on Feb 25, 2020. It is now read-only.

Commit 9b69ef8

Browse files
committed
feat: add a JUMP_TO action for switch
Add a JUMP_TO action in switch navigator to handle navigation actions explictly instead of the magical NAVIGATE action.
1 parent 65bfb4a commit 9b69ef8

14 files changed

+105
-87
lines changed

src/NavigationActions.js

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
1-
const BACK = 'Navigation/BACK';
2-
const INIT = 'Navigation/INIT';
3-
const NAVIGATE = 'Navigation/NAVIGATE';
4-
const SET_PARAMS = 'Navigation/SET_PARAMS';
1+
// Action constants
2+
export const BACK = 'Navigation/BACK';
3+
export const INIT = 'Navigation/INIT';
4+
export const NAVIGATE = 'Navigation/NAVIGATE';
5+
export const SET_PARAMS = 'Navigation/SET_PARAMS';
56

6-
const back = (payload = {}) => ({
7+
// Action creators
8+
export const back = (payload = {}) => ({
79
type: BACK,
810
key: payload.key,
911
immediate: payload.immediate,
1012
});
1113

12-
const init = (payload = {}) => {
14+
export const init = (payload = {}) => {
1315
const action = {
1416
type: INIT,
1517
};
@@ -19,7 +21,7 @@ const init = (payload = {}) => {
1921
return action;
2022
};
2123

22-
const navigate = payload => {
24+
export const navigate = payload => {
2325
const action = {
2426
type: NAVIGATE,
2527
routeName: payload.routeName,
@@ -36,22 +38,9 @@ const navigate = payload => {
3638
return action;
3739
};
3840

39-
const setParams = payload => ({
41+
export const setParams = payload => ({
4042
type: SET_PARAMS,
4143
key: payload.key,
4244
params: payload.params,
45+
preserveFocus: true,
4346
});
44-
45-
export default {
46-
// Action constants
47-
BACK,
48-
INIT,
49-
NAVIGATE,
50-
SET_PARAMS,
51-
52-
// Action creators
53-
back,
54-
init,
55-
navigate,
56-
setParams,
57-
};

src/__tests__/NavigationActions-test.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import NavigationActions from '../NavigationActions';
1+
import * as NavigationActions from '../NavigationActions';
22

33
describe('generic navigation actions', () => {
44
const params = { foo: 'bar' };
@@ -51,6 +51,7 @@ describe('generic navigation actions', () => {
5151
).toEqual({
5252
type: NavigationActions.SET_PARAMS,
5353
key: 'test',
54+
preserveFocus: true,
5455
params,
5556
});
5657
});

src/index.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,13 @@ module.exports = {
2828

2929
// Actions
3030
get NavigationActions() {
31-
return require('./NavigationActions').default;
31+
return require('./NavigationActions');
3232
},
3333
get StackActions() {
34-
return require('./routers/StackActions').default;
34+
return require('./routers/StackActions');
35+
},
36+
get SwitchActions() {
37+
return require('./routers/SwitchActions');
3538
},
3639

3740
// Routers

src/routers/StackActions.js

Lines changed: 14 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,38 @@
1-
const POP = 'Navigation/POP';
2-
const POP_TO_TOP = 'Navigation/POP_TO_TOP';
3-
const PUSH = 'Navigation/PUSH';
4-
const RESET = 'Navigation/RESET';
5-
const REPLACE = 'Navigation/REPLACE';
6-
const COMPLETE_TRANSITION = 'Navigation/COMPLETE_TRANSITION';
7-
8-
const pop = payload => ({
1+
export const POP = 'Navigation/POP';
2+
export const POP_TO_TOP = 'Navigation/POP_TO_TOP';
3+
export const PUSH = 'Navigation/PUSH';
4+
export const RESET = 'Navigation/RESET';
5+
export const REPLACE = 'Navigation/REPLACE';
6+
export const COMPLETE_TRANSITION = 'Navigation/COMPLETE_TRANSITION';
7+
8+
export const pop = payload => ({
99
type: POP,
1010
...payload,
1111
});
1212

13-
const popToTop = payload => ({
13+
export const popToTop = payload => ({
1414
type: POP_TO_TOP,
1515
...payload,
1616
});
1717

18-
const push = payload => ({
18+
export const push = payload => ({
1919
type: PUSH,
2020
...payload,
2121
});
2222

23-
const reset = payload => ({
23+
export const reset = payload => ({
2424
type: RESET,
2525
key: null,
2626
...payload,
2727
});
2828

29-
const replace = payload => ({
29+
export const replace = payload => ({
3030
type: REPLACE,
3131
...payload,
3232
});
3333

34-
const completeTransition = payload => ({
34+
export const completeTransition = payload => ({
3535
type: COMPLETE_TRANSITION,
36+
preserveFocus: true,
3637
...payload,
3738
});
38-
39-
export default {
40-
POP,
41-
POP_TO_TOP,
42-
PUSH,
43-
RESET,
44-
REPLACE,
45-
COMPLETE_TRANSITION,
46-
47-
pop,
48-
popToTop,
49-
push,
50-
reset,
51-
replace,
52-
completeTransition,
53-
};

src/routers/StackRouter.js

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import NavigationActions from '../NavigationActions';
2-
import StackActions from './StackActions';
1+
import * as NavigationActions from '../NavigationActions';
2+
import * as StackActions from './StackActions';
33
import createConfigGetter from './createConfigGetter';
44
import getScreenForRouteName from './getScreenForRouteName';
55
import StateUtils from '../StateUtils';
@@ -577,11 +577,9 @@ export default (routeConfigs, stackConfig = {}) => {
577577
state,
578578
childRoute.key,
579579
route,
580-
// the following tells replaceAt to NOT change the index to this route for the setParam action or complete transition action,
581-
// because people don't expect these actions to switch the active route
582-
action.type === NavigationActions.SET_PARAMS ||
583-
action.type === StackActions.COMPLETE_TRANSITION ||
584-
action.type.includes('DRAWER')
580+
// People don't expect these actions to switch the active route
581+
// TODO: We should switch to action.preserveFocus: true for drawer in future
582+
action.preserveFocus || action.type.includes('DRAWER')
585583
);
586584
}
587585
}

src/routers/SwitchActions.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
export const JUMP_TO = 'Navigation/JUMP_TO';
2+
3+
export const jumpTo = (payload: {
4+
routeName: string;
5+
key: string;
6+
params?: object;
7+
}) => ({
8+
type: JUMP_TO,
9+
preserveFocus: true,
10+
...payload,
11+
});

src/routers/SwitchRouter.js

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,13 @@ import invariant from '../utils/invariant';
22
import getScreenForRouteName from './getScreenForRouteName';
33
import createConfigGetter from './createConfigGetter';
44

5-
import NavigationActions from '../NavigationActions';
6-
import StackActions from './StackActions';
5+
import * as NavigationActions from '../NavigationActions';
6+
import * as SwitchActions from './SwitchActions';
77
import validateRouteConfigMap from './validateRouteConfigMap';
88
import { createPathParser } from './pathUtils';
99

1010
const defaultActionCreators = () => ({});
1111

12-
function childrenUpdateWithoutSwitchingIndex(actionType) {
13-
return [
14-
NavigationActions.SET_PARAMS,
15-
// Todo: make SwitchRouter not depend on StackActions..
16-
StackActions.COMPLETE_TRANSITION,
17-
].includes(actionType);
18-
}
19-
2012
export default (routeConfigs, config = {}) => {
2113
// Fail fast on invalid route definitions
2214
validateRouteConfigMap(routeConfigs);
@@ -172,6 +164,43 @@ export default (routeConfigs, config = {}) => {
172164
}
173165
}
174166

167+
if (
168+
action.type === SwitchActions.JUMP_TO &&
169+
(action.key == null || action.key === state.key)
170+
) {
171+
const { params } = action;
172+
const index = state.routes.findIndex(
173+
route => route.routeName === action.routeName
174+
);
175+
176+
if (index === -1) {
177+
throw new Error(
178+
`There is no route named '${
179+
action.routeName
180+
}' in the navigator with the key '${action.key}'.\n` +
181+
`Must be one of: ${state.routes
182+
.map(route => `'${route.routeName}'`)
183+
.join(',')}`
184+
);
185+
}
186+
187+
return getNextState(action, prevState, {
188+
...state,
189+
routes: state.routes.map((route, i) =>
190+
i === index
191+
? {
192+
...route,
193+
params: {
194+
...route.params,
195+
...params,
196+
},
197+
}
198+
: route
199+
),
200+
index,
201+
});
202+
}
203+
175204
// Let the current child handle it
176205
const activeChildLastState = state.routes[state.index];
177206
const activeChildRouter = childRouters[order[state.index]];
@@ -329,9 +358,7 @@ export default (routeConfigs, config = {}) => {
329358

330359
// Nested routers can be updated after switching children with actions such as SET_PARAMS
331360
// and COMPLETE_TRANSITION.
332-
// NOTE: This may be problematic with custom routers because we whitelist the actions
333-
// that can be handled by child routers without automatically changing index.
334-
if (childrenUpdateWithoutSwitchingIndex(action.type)) {
361+
if (action.preserveFocus) {
335362
index = state.index;
336363
}
337364

src/routers/__tests__/PathHandling-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import React from 'react';
55
import SwitchRouter from '../SwitchRouter';
66
import StackRouter from '../StackRouter';
77
import TabRouter from '../TabRouter';
8-
import NavigationActions from '../../NavigationActions';
8+
import * as NavigationActions from '../../NavigationActions';
99
import { _TESTING_ONLY_normalize_keys } from '../KeyGenerator.ts';
1010

1111
beforeEach(() => {

src/routers/__tests__/Routers-test.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import StackRouter from '../StackRouter';
66
import TabRouter from '../TabRouter';
77
import SwitchRouter from '../SwitchRouter';
88

9-
import NavigationActions from '../../NavigationActions';
9+
import * as NavigationActions from '../../NavigationActions';
10+
import * as StackActions from '../StackActions';
1011
import { _TESTING_ONLY_normalize_keys } from '../KeyGenerator.ts';
1112

1213
beforeEach(() => {
@@ -392,14 +393,16 @@ it('Does not switch tab index when TabRouter child handles COMPLETE_NAVIGATION o
392393

393394
const stateAfterCompleteTransition = TestRouter.getStateForAction(
394395
{
395-
type: NavigationActions.COMPLETE_TRANSITION,
396+
type: StackActions.COMPLETE_TRANSITION,
397+
preserveFocus: true,
396398
key: state2.routes[0].key,
397399
},
398400
state3
399401
);
400402
const stateAfterSetParams = TestRouter.getStateForAction(
401403
{
402404
type: NavigationActions.SET_PARAMS,
405+
preserveFocus: true,
403406
key: state1.routes[0].routes[0].key,
404407
params: { key: 'value' },
405408
},

src/routers/__tests__/StackRouter-test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
import React from 'react';
44

55
import StackRouter from '../StackRouter';
6-
import StackActions from '../StackActions';
7-
import NavigationActions from '../../NavigationActions';
6+
import * as StackActions from '../StackActions';
7+
import * as NavigationActions from '../../NavigationActions';
88
import { _TESTING_ONLY_normalize_keys } from '../KeyGenerator.ts';
99

1010
beforeEach(() => {

0 commit comments

Comments
 (0)