mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-03-06 22:39:41 +08:00
Use redux constants and action creator functions (#120)
This commit is contained in:
@@ -78,7 +78,7 @@ const MyAppRouter = {
|
||||
getStateForAction(action, state) {
|
||||
if (
|
||||
state &&
|
||||
action.type === 'Back' &&
|
||||
action.type === NavigationActions.BACK &&
|
||||
state.routes[state.index].params.isEditing
|
||||
) {
|
||||
// Returning null from getStateForAction means that the action
|
||||
@@ -97,6 +97,8 @@ Perhaps your app has a unique URI which the built-in routers cannot handle. You
|
||||
|
||||
```js
|
||||
|
||||
import { NavigationActions } from 'react-navigation'
|
||||
|
||||
const MyApp = StackNavigator({
|
||||
Home: { screen: HomeScreen },
|
||||
Profile: { screen: ProfileScreen },
|
||||
@@ -111,17 +113,15 @@ MyApp.router = {
|
||||
params.magic === 'yes'
|
||||
) {
|
||||
// returns a profile navigate action for /my/custom/path?magic=yes
|
||||
return {
|
||||
type: 'Navigate',
|
||||
return NavigationActions.navigate({
|
||||
routeName: 'Profile',
|
||||
action: {
|
||||
action: NavigationActions.navigate({
|
||||
// This child action will get passed to the child router
|
||||
// ProfileScreen.router.getStateForAction to get the child
|
||||
// navigation state.
|
||||
type: 'Navigate',
|
||||
routeName: 'Friends',
|
||||
},
|
||||
};
|
||||
}),
|
||||
});
|
||||
return null;
|
||||
}
|
||||
return MyApp.router.getStateForAction(action, state);
|
||||
|
||||
@@ -56,8 +56,8 @@ A navigation-aware component that hosts other navigation-aware components. Most
|
||||
The navigation prop should be provided to components who need access to navigation. If provided, it must follow this interface:
|
||||
|
||||
```javascript
|
||||
type BackAction = {type: 'Back'};
|
||||
type URIAction = {type: 'URI', uri: string};
|
||||
type BackAction = {type: 'Navigation/BACK'};
|
||||
type URIAction = {type: 'Navigation/URI', uri: string};
|
||||
|
||||
interface Navigation<S, A> {
|
||||
dispatch(action: (A | BackAction | URIAction)): boolean;
|
||||
@@ -81,7 +81,7 @@ const MyView = ({ navigation }) => {
|
||||
|
||||
#### navigation.dispatch(action)
|
||||
|
||||
The channel that a component can call to request navigation from its parent. When calling `dispatch`, you must provide an action object with a `type`. There are two special action types: 'Back' and 'URI'.
|
||||
The channel that a component can call to request navigation from its parent. When calling `dispatch`, you must provide an action object with a `type`. There are two special action types: 'Navigation/BACK' and 'Navigation/URI'.
|
||||
|
||||
```javascript
|
||||
const MyLink = ({ navigation }) => (
|
||||
@@ -102,8 +102,8 @@ const MyLink = ({ navigation }) => (
|
||||
A router object may be statically defined on your component. If defined, it must follow this interface:
|
||||
|
||||
```javascript
|
||||
type BackAction = {type: 'Back'};
|
||||
type URIAction = {type: 'URI', uri: string};
|
||||
type BackAction = {type: 'Navigation/BACK'};
|
||||
type URIAction = {type: 'Navigation/URI', uri: string};
|
||||
|
||||
interface Router<S, A> {
|
||||
getStateForAction(action: (A | BackAction | URIAction), lastState: ?S): ?S;
|
||||
@@ -151,7 +151,7 @@ There are two special actions that can be fired into `navigation.dispatch` and c
|
||||
This action means the same thing as an Android back button press.
|
||||
|
||||
```
|
||||
type BackAction = { type: 'Back' };
|
||||
type BackAction = { type: 'Navigation/BACK' };
|
||||
```
|
||||
|
||||
#### URI Open Action
|
||||
@@ -159,7 +159,7 @@ type BackAction = { type: 'Back' };
|
||||
Used to request the enclosing app or OS to open a link at a particular URI. If it is a web URI like `http` or `https`, the app may open a WebView to present the page. Or the app may open the URI in a web browser. In some cases, an app may choose to block a URI action or handle it differently.
|
||||
|
||||
```
|
||||
type URIAction = { type: 'URI', uri: string };
|
||||
type URIAction = { type: 'Navigation/URI', uri: string };
|
||||
```
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ To block the Android back button:
|
||||
class Foo extends React.Component {
|
||||
static router = {
|
||||
getStateForAction(action, prevState = {}) {
|
||||
if (action.type === 'Back') return null;
|
||||
if (action.type === 'Navigation/BACK') return null;
|
||||
else return prevState;
|
||||
},
|
||||
};
|
||||
|
||||
@@ -19,7 +19,7 @@ class MyNavigationAwareComponent extends React.Component {
|
||||
const state = lastState = { myMode: 'default' };
|
||||
if (action.type === 'MyAction') {
|
||||
return { myMode: 'action' };
|
||||
} else if (action.type === 'Back') {
|
||||
} else if (action.type === NavigationActions.BACK) {
|
||||
return { myMode: 'blockBackButton' };
|
||||
} else {
|
||||
return state;
|
||||
|
||||
@@ -79,7 +79,7 @@ class InfraScreen extends React.Component {
|
||||
HybridNavigationModule.openURI(action.uri);
|
||||
return true;
|
||||
}
|
||||
if (action.type === 'Back') {
|
||||
if (action.type === NavigationActions.BACK) {
|
||||
HybridNavigationModule.goBack();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -102,18 +102,21 @@ Optionally provide a key, which specifies the route to go back from. By default,
|
||||
|
||||
Use dispatch to send any navigation action to the router. The other navigation functions use dispatch behind the scenes.
|
||||
|
||||
Note that if you want to dispatch react-navigation actions you should use the action creators provided in this library.
|
||||
|
||||
The following actions are supported:
|
||||
|
||||
### Navigate
|
||||
```js
|
||||
{
|
||||
type: 'Navigate',
|
||||
import { NavigationActions } from 'react-navigation'
|
||||
|
||||
NavigationActions.navigate({
|
||||
routeName: 'Profile',
|
||||
params: {},
|
||||
|
||||
// navigate can have a nested navigate action that will be run inside the child router
|
||||
action: {type: 'Navigate', routeName: 'SubProfileRoute'}
|
||||
}
|
||||
action: NavigationActions.navigate({ routeName: 'SubProfileRoute'})
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
@@ -122,10 +125,11 @@ The following actions are supported:
|
||||
The `Reset` action wipes the whole navigation state and replaces it with the result of several actions.
|
||||
|
||||
```js
|
||||
{
|
||||
type: 'Reset',
|
||||
actions: ,
|
||||
}
|
||||
import { NavigationActions } from 'react-navigation'
|
||||
|
||||
NavigationActions.reset({
|
||||
actions: NavigationActions.navigate({ routeName: 'Profile'}),
|
||||
})
|
||||
```
|
||||
|
||||
### SetParams
|
||||
@@ -133,10 +137,11 @@ The `Reset` action wipes the whole navigation state and replaces it with the res
|
||||
When dispatching `SetParams`, the router will produce a new state that has changed the params of a particular route, as identified by the key
|
||||
|
||||
```js
|
||||
{
|
||||
type: 'SetParams',
|
||||
import { NavigationActions } from 'react-navigation'
|
||||
|
||||
NavigationActions.setParams({
|
||||
params: {}, // these are the new params that will be merged into the existing route params
|
||||
// The key of the route that should get the new params
|
||||
key: 'screen-123',
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
NativeModules,
|
||||
} from 'react-native';
|
||||
import {
|
||||
NavigationActions,
|
||||
addNavigationHelpers,
|
||||
} from 'react-navigation';
|
||||
|
||||
@@ -22,7 +23,7 @@ const HybridContainer = (ReactScreens) => {
|
||||
let ScreenView = ReactScreens[name];
|
||||
let screenKey = name;
|
||||
let navState = null;
|
||||
const action = { type: 'Navigate', routeName: name, params };
|
||||
const action = NavigationActions.navigate({ routeName: name, params };
|
||||
if (!ScreenView) {
|
||||
// Deep linking magic here. Try each screen to see if the state changes
|
||||
// in response to this action. The first screen who returns
|
||||
@@ -33,7 +34,7 @@ const HybridContainer = (ReactScreens) => {
|
||||
if (!V || !V.router || !V.router.getStateForAction) {
|
||||
return;
|
||||
}
|
||||
const baseState = V.router.getStateForAction({ type: 'Init' });
|
||||
const baseState = V.router.getStateForAction(NavigationActions.init());
|
||||
const linkedState = V.router.getStateForAction(action, baseState);
|
||||
if (baseState !== linkedState) {
|
||||
ScreenView = V;
|
||||
@@ -77,7 +78,7 @@ const HybridContainer = (ReactScreens) => {
|
||||
this.setState({ navState });
|
||||
return true;
|
||||
}
|
||||
if (action.type === 'Navigate') {
|
||||
if (action.type === NavigationActions.NAVIGATE) {
|
||||
HybridNavigationManager.navigate(action.routeName, action.params || {});
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
View,
|
||||
} from 'react-native';
|
||||
import {
|
||||
NavigationActions,
|
||||
addNavigationHelpers,
|
||||
StackNavigator,
|
||||
} from 'react-navigation';
|
||||
@@ -70,7 +71,7 @@ const LoginStatusMessage = connect(state => ({
|
||||
{'You are "logged in" right now'}
|
||||
</Text>
|
||||
<Button
|
||||
onPress={() => dispatch({ type: 'Navigate', routeName: 'Profile' })}
|
||||
onPress={() => dispatch(NavigationActions.navigate({ routeName: 'Profile' }))}
|
||||
title="Profile"
|
||||
/>
|
||||
</View>
|
||||
@@ -81,7 +82,7 @@ const AuthButton = connect(state => ({
|
||||
isLoggedIn: state.auth.isLoggedIn,
|
||||
}), dispatch => ({
|
||||
logout: () => dispatch({ type: 'Logout' }),
|
||||
login: () => dispatch({ type: 'Navigate', routeName: 'Login' }),
|
||||
login: () => dispatch(NavigationActions.navigate({ routeName: 'Login' })),
|
||||
}))(({ logout, login, isLoggedIn }) => (
|
||||
<Button
|
||||
title={isLoggedIn ? 'Log Out' : 'Log In'}
|
||||
@@ -124,10 +125,10 @@ const initialAuthState = { isLoggedIn: false };
|
||||
const AppReducer = combineReducers({
|
||||
nav: (state = initialNavState, action) => {
|
||||
if (action.type === 'Login') {
|
||||
return AppNavigator.router.getStateForAction({ type: 'Back' }, state);
|
||||
return AppNavigator.router.getStateForAction(NavigationActions.back(), state);
|
||||
}
|
||||
if (action.type === 'Logout') {
|
||||
return AppNavigator.router.getStateForAction({ type: 'Navigate', routeName: 'Login' }, state);
|
||||
return AppNavigator.router.getStateForAction(NavigationActions.navigate({ routeName: 'Login' }), state);
|
||||
}
|
||||
return AppNavigator.router.getStateForAction(action, state);
|
||||
},
|
||||
|
||||
70
packages/react-navigation/src/NavigationActions.js
vendored
Normal file
70
packages/react-navigation/src/NavigationActions.js
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
const namespacedAction = (action: string) => `Navigation/${action}`;
|
||||
|
||||
const BACK = namespacedAction('BACK');
|
||||
const INIT = namespacedAction('INIT');
|
||||
const NAVIGATE = namespacedAction('NAVIGATE');
|
||||
const RESET = namespacedAction('RESET');
|
||||
const SET_PARAMS = namespacedAction('SET_PARAMS');
|
||||
const URI = namespacedAction('URI');
|
||||
|
||||
const createAction = (type: string) => (payload: object = {}) => ({
|
||||
type,
|
||||
...payload,
|
||||
});
|
||||
|
||||
const back = createAction(BACK);
|
||||
const init = createAction(INIT);
|
||||
const navigate = createAction(NAVIGATE);
|
||||
const reset = createAction(RESET);
|
||||
const setParams = createAction(SET_PARAMS);
|
||||
const uri = createAction(URI);
|
||||
|
||||
const deprecatedActionMap = {
|
||||
Back: BACK,
|
||||
Init: INIT,
|
||||
Navigate: NAVIGATE,
|
||||
Reset: RESET,
|
||||
SetParams: SET_PARAMS,
|
||||
Uri: URI,
|
||||
};
|
||||
|
||||
const mapDeprecatedActionAndWarn = (action: object) => {
|
||||
const mappedType = deprecatedActionMap[action.type];
|
||||
if (!mappedType) { return action; }
|
||||
|
||||
console.warn([
|
||||
`The action type '${action.type}' has been renamed to '${mappedType}'.`,
|
||||
`'${action.type}' will continue to work while in beta but will be removed`,
|
||||
'in the first major release. Moving forward, you should use the',
|
||||
'action constants and action creators exported by this library in',
|
||||
"the 'actions' object.",
|
||||
'See https://github.com/react-community/react-navigation/pull/120 for',
|
||||
'more details.',
|
||||
].join(' '));
|
||||
|
||||
return {
|
||||
...action,
|
||||
type: deprecatedActionMap[action.type],
|
||||
};
|
||||
};
|
||||
|
||||
export default {
|
||||
// Action constants
|
||||
BACK,
|
||||
INIT,
|
||||
NAVIGATE,
|
||||
RESET,
|
||||
SET_PARAMS,
|
||||
URI,
|
||||
|
||||
// Action creators
|
||||
back,
|
||||
init,
|
||||
navigate,
|
||||
reset,
|
||||
setParams,
|
||||
uri,
|
||||
|
||||
// TODO: Remove once old actions are deprecated
|
||||
mapDeprecatedActionAndWarn,
|
||||
};
|
||||
17
packages/react-navigation/src/TypeDefinition.js
vendored
17
packages/react-navigation/src/TypeDefinition.js
vendored
@@ -203,7 +203,7 @@ export type NavigationParams = {
|
||||
};
|
||||
|
||||
export type NavigationNavigateAction = {
|
||||
type: 'Navigate',
|
||||
type: 'Navigation/NAVIGATE',
|
||||
routeName: string,
|
||||
params?: NavigationParams,
|
||||
|
||||
@@ -212,12 +212,12 @@ export type NavigationNavigateAction = {
|
||||
};
|
||||
|
||||
export type NavigationBackAction = {
|
||||
type: 'Back',
|
||||
type: 'Navigation/BACK',
|
||||
key?: ?string,
|
||||
};
|
||||
|
||||
export type NavigationSetParamsAction = {
|
||||
type: 'SetParams',
|
||||
type: 'Navigation/SET_PARAMS',
|
||||
|
||||
// The key of the route where the params should be set
|
||||
key: string,
|
||||
@@ -227,15 +227,20 @@ export type NavigationSetParamsAction = {
|
||||
};
|
||||
|
||||
export type NavigationInitAction = {
|
||||
type: 'Init',
|
||||
type: 'Navigation/INIT',
|
||||
};
|
||||
|
||||
export type NavigationResetAction = {
|
||||
type: 'Reset',
|
||||
type: 'Navigation/RESET',
|
||||
index: number,
|
||||
actions: Array<NavigationNavigateAction>,
|
||||
};
|
||||
|
||||
export type NavigationUriAction = {
|
||||
type: 'Navigation/URI',
|
||||
uri: string,
|
||||
};
|
||||
|
||||
export type NavigationContainerOptions = {
|
||||
// This is used to extract the path from the URI passed to the app for a deep link
|
||||
URIPrefix?: string,
|
||||
@@ -302,7 +307,7 @@ export type NavigationTabRouterConfig = {
|
||||
paths?: NavigationPathsConfig,
|
||||
navigationOptions?: NavigationScreenOptions,
|
||||
order?: Array<string>, // todo: type these as the real route names rather than 'string'
|
||||
|
||||
|
||||
// Does the back button cause the router to switch to the initial tab
|
||||
backBehavior?: 'none' | 'initialRoute', // defaults `initialRoute`
|
||||
};
|
||||
|
||||
37
packages/react-navigation/src/__tests__/NavigationActions-test.js
vendored
Normal file
37
packages/react-navigation/src/__tests__/NavigationActions-test.js
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
/* @flow */
|
||||
|
||||
import NavigationActions from '../NavigationActions';
|
||||
|
||||
describe('actions', () => {
|
||||
const data = { foo: 'bar' };
|
||||
|
||||
it('exports back action and type', () => {
|
||||
expect(NavigationActions.back()).toEqual({ type: NavigationActions.BACK });
|
||||
expect(NavigationActions.back(data)).toEqual({ type: NavigationActions.BACK, ...data });
|
||||
});
|
||||
|
||||
it('exports init action and type', () => {
|
||||
expect(NavigationActions.init()).toEqual({ type: NavigationActions.INIT });
|
||||
expect(NavigationActions.init(data)).toEqual({ type: NavigationActions.INIT, ...data });
|
||||
});
|
||||
|
||||
it('exports navigate action and type', () => {
|
||||
expect(NavigationActions.navigate()).toEqual({ type: NavigationActions.NAVIGATE });
|
||||
expect(NavigationActions.navigate(data)).toEqual({ type: NavigationActions.NAVIGATE, ...data });
|
||||
});
|
||||
|
||||
it('exports reset action and type', () => {
|
||||
expect(NavigationActions.reset()).toEqual({ type: NavigationActions.RESET });
|
||||
expect(NavigationActions.reset(data)).toEqual({ type: NavigationActions.RESET, ...data });
|
||||
});
|
||||
|
||||
it('exports setParams action and type', () => {
|
||||
expect(NavigationActions.setParams()).toEqual({ type: NavigationActions.SET_PARAMS });
|
||||
expect(NavigationActions.setParams(data)).toEqual({ type: NavigationActions.SET_PARAMS, ...data });
|
||||
});
|
||||
|
||||
it('exports uri action and type', () => {
|
||||
expect(NavigationActions.uri()).toEqual({ type: NavigationActions.URI });
|
||||
expect(NavigationActions.uri(data)).toEqual({ type: NavigationActions.URI, ...data });
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,6 @@
|
||||
/* @flow */
|
||||
|
||||
import NavigationActions from '../NavigationActions';
|
||||
import addNavigationHelpers from '../addNavigationHelpers';
|
||||
|
||||
describe('addNavigationHelpers', () => {
|
||||
@@ -9,7 +10,7 @@ describe('addNavigationHelpers', () => {
|
||||
state: { key: 'A', routeName: 'Home' },
|
||||
dispatch: mockedDispatch,
|
||||
}).goBack('A')).toEqual(true);
|
||||
expect(mockedDispatch).toBeCalledWith({ type: 'Back', key: 'A' });
|
||||
expect(mockedDispatch).toBeCalledWith({ type: NavigationActions.BACK, key: 'A' });
|
||||
expect(mockedDispatch.mock.calls.length).toBe(1);
|
||||
});
|
||||
|
||||
@@ -19,7 +20,7 @@ describe('addNavigationHelpers', () => {
|
||||
state: {},
|
||||
dispatch: mockedDispatch,
|
||||
}).goBack()).toEqual(true);
|
||||
expect(mockedDispatch).toBeCalledWith({ type: 'Back' });
|
||||
expect(mockedDispatch).toBeCalledWith({ type: NavigationActions.BACK });
|
||||
expect(mockedDispatch.mock.calls.length).toBe(1);
|
||||
});
|
||||
|
||||
@@ -30,7 +31,7 @@ describe('addNavigationHelpers', () => {
|
||||
dispatch: mockedDispatch,
|
||||
}).navigate('Profile', { name: 'Matt' })).toEqual(true);
|
||||
expect(mockedDispatch).toBeCalledWith({
|
||||
type: 'Navigate',
|
||||
type: NavigationActions.NAVIGATE,
|
||||
params: { name: 'Matt' },
|
||||
routeName: 'Profile',
|
||||
});
|
||||
@@ -44,7 +45,7 @@ describe('addNavigationHelpers', () => {
|
||||
dispatch: mockedDispatch,
|
||||
}).setParams({ notificationsEnabled: true })).toEqual(true);
|
||||
expect(mockedDispatch).toBeCalledWith({
|
||||
type: 'SetParams',
|
||||
type: NavigationActions.SET_PARAMS,
|
||||
key: 'B',
|
||||
params: { notificationsEnabled: true },
|
||||
});
|
||||
|
||||
@@ -11,26 +11,31 @@ import type {
|
||||
NavigationRoute,
|
||||
} from './TypeDefinition';
|
||||
|
||||
import NavigationActions from './NavigationActions'
|
||||
|
||||
export default (navigation: NavigationProp<NavigationRoute, NavigationAction>): NavigationScreenProp<NavigationRoute, NavigationAction> => ({
|
||||
...navigation,
|
||||
goBack: (key): boolean => {
|
||||
return navigation.dispatch({
|
||||
type: 'Back',
|
||||
return navigation.dispatch(NavigationActions.back({
|
||||
key: key === undefined ? navigation.state.key : key,
|
||||
});
|
||||
}));
|
||||
},
|
||||
navigate: (routeName, params, action): boolean => {
|
||||
return navigation.dispatch({
|
||||
type: 'Navigate',
|
||||
return navigation.dispatch(NavigationActions.navigate({
|
||||
routeName,
|
||||
params,
|
||||
action,
|
||||
});
|
||||
}));
|
||||
},
|
||||
/**
|
||||
* For updating current route params. For example the nav bar title and
|
||||
* buttons are based on the route params.
|
||||
* This means `setParams` can be used to update nav bar for example.
|
||||
*/
|
||||
setParams: params => navigation.dispatch({ type: 'SetParams', params, key: navigation.state.key }),
|
||||
setParams: (params): boolean => {
|
||||
return navigation.dispatch(NavigationActions.setParams({
|
||||
params,
|
||||
key: navigation.state.key
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
Linking,
|
||||
} from 'react-native';
|
||||
import invariant from 'fbjs/lib/invariant';
|
||||
import NavigationActions from './NavigationActions';
|
||||
import addNavigationHelpers from './addNavigationHelpers';
|
||||
|
||||
import type {
|
||||
@@ -77,7 +78,7 @@ const createNavigationContainer = (
|
||||
this.state = null;
|
||||
if (this._isStateful()) {
|
||||
this.state = {
|
||||
nav: Component.router.getStateForAction({ type: 'Init' }),
|
||||
nav: Component.router.getStateForAction(NavigationActions.init()),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -85,7 +86,7 @@ const createNavigationContainer = (
|
||||
componentDidMount() {
|
||||
if (this._isStateful()) {
|
||||
this.subs = BackAndroid.addEventListener('backPress', () =>
|
||||
this.dispatch({ type: 'Back' })
|
||||
this.dispatch(NavigationActions.back())
|
||||
);
|
||||
Linking.addEventListener('url', this._handleOpenURL);
|
||||
Linking.getInitialURL().then((url: string) => {
|
||||
|
||||
@@ -9,6 +9,7 @@ module.exports = {
|
||||
get StateUtils() { return require('./StateUtils').default; },
|
||||
get PropTypes() { return require('./PropTypes').default; },
|
||||
get addNavigationHelpers() { return require('./addNavigationHelpers').default; },
|
||||
get NavigationActions() { return require('./NavigationActions').default; },
|
||||
|
||||
// Navigators
|
||||
get createNavigator() { return require('./navigators/createNavigator').default; },
|
||||
|
||||
@@ -9,6 +9,7 @@ module.exports = {
|
||||
get StateUtils() { return require('./StateUtils').default; },
|
||||
get PropTypes() { return require('./PropTypes').default; },
|
||||
get addNavigationHelpers() { return require('./addNavigationHelpers').default; },
|
||||
get NavigationActions() { return require('./NavigationActions').default; },
|
||||
|
||||
// Navigators
|
||||
get createNavigator() { return require('./navigators/createNavigator').default; },
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import pathToRegexp from 'path-to-regexp';
|
||||
|
||||
import NavigationActions from '../NavigationActions';
|
||||
import createConfigGetter from './createConfigGetter';
|
||||
import getScreenForRouteName from './getScreenForRouteName';
|
||||
import StateUtils from '../StateUtils';
|
||||
@@ -90,10 +91,12 @@ export default (
|
||||
},
|
||||
|
||||
getStateForAction(action: NavigationStackAction, state: ?NavigationState) {
|
||||
action = NavigationActions.mapDeprecatedActionAndWarn(action)
|
||||
|
||||
// Set up the initial state if needed
|
||||
if (!state) {
|
||||
let route = {};
|
||||
if (action.type === 'Navigate' && (childRouters[action.routeName] !== undefined)) {
|
||||
if (action.type === NavigationActions.NAVIGATE && (childRouters[action.routeName] !== undefined)) {
|
||||
return {
|
||||
index: 0,
|
||||
routes: [
|
||||
@@ -106,11 +109,10 @@ export default (
|
||||
};
|
||||
}
|
||||
if (initialChildRouter) {
|
||||
route = initialChildRouter.getStateForAction({
|
||||
type: 'Navigate',
|
||||
route = initialChildRouter.getStateForAction(NavigationActions.navigate({
|
||||
routeName: initialRouteName,
|
||||
params: initialRouteParams,
|
||||
});
|
||||
}));
|
||||
}
|
||||
route = {
|
||||
...route,
|
||||
@@ -134,13 +136,13 @@ export default (
|
||||
}
|
||||
|
||||
// Handle push/pop
|
||||
if (action.type === 'Navigate' && childRouters[action.routeName] !== undefined) {
|
||||
if (action.type === NavigationActions.NAVIGATE && childRouters[action.routeName] !== undefined) {
|
||||
const childRouter = childRouters[action.routeName];
|
||||
let route;
|
||||
if (childRouter) {
|
||||
route = {
|
||||
...action,
|
||||
...childRouter.getStateForAction(action.action || { type: 'Init' }),
|
||||
...childRouter.getStateForAction(action.action || NavigationActions.init()),
|
||||
key: _getUuid(),
|
||||
routeName: action.routeName,
|
||||
};
|
||||
@@ -154,7 +156,7 @@ export default (
|
||||
return StateUtils.push(state, route);
|
||||
}
|
||||
|
||||
if (action.type === 'SetParams') {
|
||||
if (action.type === NavigationActions.SET_PARAMS) {
|
||||
const lastRoute = state.routes.find(route => route.key === action.key);
|
||||
if (lastRoute) {
|
||||
const params = {
|
||||
@@ -173,7 +175,7 @@ export default (
|
||||
}
|
||||
}
|
||||
|
||||
if (action.type === 'Reset') {
|
||||
if (action.type === NavigationActions.RESET) {
|
||||
const resetAction = ((action: any): NavigationResetAction);
|
||||
|
||||
return {
|
||||
@@ -199,7 +201,7 @@ export default (
|
||||
};
|
||||
}
|
||||
|
||||
if (action.type === 'Back') {
|
||||
if (action.type === NavigationActions.BACK) {
|
||||
let backRouteIndex = null;
|
||||
if (action.key) {
|
||||
const backRoute = state.routes.find(route => route.key === action.key);
|
||||
@@ -230,10 +232,9 @@ export default (
|
||||
// If the path is empty (null or empty string)
|
||||
// just return the initial route action
|
||||
if (!pathToResolve) {
|
||||
return {
|
||||
type: 'Navigate',
|
||||
return NavigationActions.navigate({
|
||||
routeName: initialRouteName,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// Attempt to match `pathToResolve` with a route in this router's
|
||||
@@ -280,12 +281,11 @@ export default (
|
||||
return result;
|
||||
}, null);
|
||||
|
||||
return {
|
||||
type: 'Navigate',
|
||||
return NavigationActions.navigate({
|
||||
routeName: matchedRouteName,
|
||||
...(params ? { params } : {}),
|
||||
...(nestedAction ? { action: nestedAction } : {}),
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
getScreenConfig: createConfigGetter(routeConfigs, stackConfig.navigationOptions),
|
||||
|
||||
@@ -7,6 +7,7 @@ import createConfigGetter from './createConfigGetter';
|
||||
import invariant from 'fbjs/lib/invariant';
|
||||
import warning from 'fbjs/lib/warning';
|
||||
|
||||
import NavigationActions from '../NavigationActions';
|
||||
import StateUtils from '../StateUtils';
|
||||
|
||||
import validateRouteConfigMap from './validateRouteConfigMap';
|
||||
@@ -22,8 +23,6 @@ import type {
|
||||
NavigationTabRouterConfig,
|
||||
} from '../TypeDefinition';
|
||||
|
||||
const INIT_ACTION = { type: 'Init' };
|
||||
|
||||
export default (
|
||||
routeConfigs: NavigationRouteConfigMap,
|
||||
config: NavigationTabRouterConfig = {}
|
||||
@@ -53,6 +52,8 @@ export default (
|
||||
);
|
||||
return {
|
||||
getStateForAction(action: NavigationAction, inputState: ?NavigationState): ?NavigationState {
|
||||
action = NavigationActions.mapDeprecatedActionAndWarn(action)
|
||||
|
||||
// Establish a default state
|
||||
let state = inputState;
|
||||
if (!state) {
|
||||
@@ -60,7 +61,7 @@ export default (
|
||||
const tabRouter = tabRouters[routeName];
|
||||
if (tabRouter) {
|
||||
return {
|
||||
...tabRouter.getStateForAction(action.action || INIT_ACTION),
|
||||
...tabRouter.getStateForAction(action.action || NavigationActions.init()),
|
||||
key: routeName,
|
||||
routeName,
|
||||
};
|
||||
@@ -99,11 +100,11 @@ export default (
|
||||
// handle the action, to allow inner tabs to change first
|
||||
let activeTabIndex = state.index;
|
||||
const isBackEligible = action.key == null || action.key === activeTabLastState.key;
|
||||
if (action.type === 'Back' && isBackEligible && shouldBackNavigateToInitialRoute) {
|
||||
if (action.type === NavigationActions.BACK && isBackEligible && shouldBackNavigateToInitialRoute) {
|
||||
activeTabIndex = initialRouteIndex;
|
||||
}
|
||||
let didNavigate = false;
|
||||
if (action.type === 'Navigate') {
|
||||
if (action.type === NavigationActions.NAVIGATE) {
|
||||
const navigateAction = ((action: any): NavigationNavigateAction);
|
||||
didNavigate = !!order.find((tabId: string, i: number) => {
|
||||
if (tabId === navigateAction.routeName) {
|
||||
@@ -225,10 +226,9 @@ export default (
|
||||
const pathToTest = paths[tabId];
|
||||
if (parts[0] === pathToTest) {
|
||||
const tabRouter = tabRouters[tabId];
|
||||
const action: NavigationNavigateAction = {
|
||||
type: 'Navigate',
|
||||
const action: NavigationNavigateAction = NavigationActions.navigate({
|
||||
routeName: tabId,
|
||||
};
|
||||
});
|
||||
if (tabRouter && tabRouter.getActionForPathAndParams) {
|
||||
action.action = tabRouter.getActionForPathAndParams(parts.slice(1).join('/'), params);
|
||||
} else if (params) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import React from 'react';
|
||||
import StackRouter from '../StackRouter';
|
||||
import TabRouter from '../TabRouter';
|
||||
|
||||
import NavigationActions from '../../NavigationActions';
|
||||
import addNavigationHelpers from '../../addNavigationHelpers';
|
||||
|
||||
const ROUTERS = {
|
||||
@@ -63,10 +64,10 @@ test('Handles no-op actions with tabs within stack router', () => {
|
||||
screen: BarView,
|
||||
},
|
||||
});
|
||||
const state1 = TestRouter.getStateForAction({ type: 'Init' });
|
||||
const state2 = TestRouter.getStateForAction({ type: 'Navigate', routeName: 'Qux' });
|
||||
const state1 = TestRouter.getStateForAction({ type: NavigationActions.INIT });
|
||||
const state2 = TestRouter.getStateForAction({ type: NavigationActions.NAVIGATE, routeName: 'Qux' });
|
||||
expect(state1).toEqual(state2);
|
||||
const state3 = TestRouter.getStateForAction({ type: 'Navigate', routeName: 'Zap' }, state2);
|
||||
const state3 = TestRouter.getStateForAction({ type: NavigationActions.NAVIGATE, routeName: 'Zap' }, state2);
|
||||
expect(state2).toEqual(state3);
|
||||
});
|
||||
|
||||
@@ -81,7 +82,7 @@ test('Handles deep action', () => {
|
||||
Bar: { screen: BarView },
|
||||
Foo: { screen: FooTabNavigator },
|
||||
});
|
||||
const state1 = TestRouter.getStateForAction({ type: 'Init' });
|
||||
const state1 = TestRouter.getStateForAction({ type: NavigationActions.INIT });
|
||||
const expectedState = {
|
||||
index: 0,
|
||||
routes: [
|
||||
@@ -92,7 +93,7 @@ test('Handles deep action', () => {
|
||||
],
|
||||
};
|
||||
expect(state1).toEqual(expectedState);
|
||||
const state2 = TestRouter.getStateForAction({ type: 'Navigate', routeName: 'Foo', action: {type: 'Navigate', routeName: 'Zoo'} }, state1);
|
||||
const state2 = TestRouter.getStateForAction({ type: NavigationActions.NAVIGATE, routeName: 'Foo', action: {type: NavigationActions.NAVIGATE, routeName: 'Zoo'} }, state1);
|
||||
expect(state2.index).toEqual(1);
|
||||
expect(state2.routes[1].index).toEqual(1);
|
||||
});
|
||||
@@ -112,9 +113,9 @@ test('Supports lazily-evaluated getScreen', () => {
|
||||
getScreen: () => BarView,
|
||||
},
|
||||
});
|
||||
const state1 = TestRouter.getStateForAction({ type: 'Init' });
|
||||
const state2 = TestRouter.getStateForAction({ type: 'Navigate', routeName: 'Qux' });
|
||||
const state1 = TestRouter.getStateForAction({ type: NavigationActions.INIT });
|
||||
const state2 = TestRouter.getStateForAction({ type: NavigationActions.NAVIGATE, routeName: 'Qux' });
|
||||
expect(state1).toEqual(state2);
|
||||
const state3 = TestRouter.getStateForAction({ type: 'Navigate', routeName: 'Zap' }, state2);
|
||||
const state3 = TestRouter.getStateForAction({ type: NavigationActions.NAVIGATE, routeName: 'Zap' }, state2);
|
||||
expect(state2).toEqual(state3);
|
||||
});
|
||||
|
||||
@@ -7,6 +7,8 @@ import React from 'react';
|
||||
import StackRouter from '../StackRouter';
|
||||
import TabRouter from '../TabRouter';
|
||||
|
||||
import NavigationActions from '../../NavigationActions';
|
||||
|
||||
const ListScreen = () => <div />;
|
||||
|
||||
const ProfileNavigator = () => <div />;
|
||||
@@ -170,14 +172,14 @@ describe('StackRouter', () => {
|
||||
|
||||
test('Parses simple paths', () => {
|
||||
expect(AuthNavigator.router.getActionForPathAndParams('login')).toEqual({
|
||||
type: 'Navigate',
|
||||
type: NavigationActions.NAVIGATE,
|
||||
routeName: 'login',
|
||||
});
|
||||
});
|
||||
|
||||
test('Parses paths with a param', () => {
|
||||
expect(TestStackRouter.getActionForPathAndParams('people/foo')).toEqual({
|
||||
type: 'Navigate',
|
||||
type: NavigationActions.NAVIGATE,
|
||||
routeName: 'person',
|
||||
params: {
|
||||
id: 'foo',
|
||||
@@ -190,10 +192,10 @@ describe('StackRouter', () => {
|
||||
const uri = 'auth/login';
|
||||
const action = TestStackRouter.getActionForPathAndParams(uri);
|
||||
expect(action).toEqual({
|
||||
type: 'Navigate',
|
||||
type: NavigationActions.NAVIGATE,
|
||||
routeName: 'auth',
|
||||
action: {
|
||||
type: 'Navigate',
|
||||
type: NavigationActions.NAVIGATE,
|
||||
routeName: 'login',
|
||||
},
|
||||
});
|
||||
@@ -203,16 +205,16 @@ describe('StackRouter', () => {
|
||||
const uri = 'main/p/4/list/10259959195';
|
||||
const action = TestStackRouter.getActionForPathAndParams(uri);
|
||||
expect(action).toEqual({
|
||||
type: 'Navigate',
|
||||
type: NavigationActions.NAVIGATE,
|
||||
routeName: 'main',
|
||||
action: {
|
||||
type: 'Navigate',
|
||||
type: NavigationActions.NAVIGATE,
|
||||
routeName: 'profile',
|
||||
params: {
|
||||
id: '4',
|
||||
},
|
||||
action: {
|
||||
type: 'Navigate',
|
||||
type: NavigationActions.NAVIGATE,
|
||||
routeName: 'list',
|
||||
params: {
|
||||
id: '10259959195',
|
||||
@@ -232,10 +234,10 @@ describe('StackRouter', () => {
|
||||
const uri = 'auth/login/2';
|
||||
const action = TestStackRouter.getActionForPathAndParams(uri);
|
||||
expect(action).toEqual({
|
||||
type: 'Navigate',
|
||||
type: NavigationActions.NAVIGATE,
|
||||
routeName: 'auth',
|
||||
action: {
|
||||
type: 'Navigate',
|
||||
type: NavigationActions.NAVIGATE,
|
||||
routeName: 'login',
|
||||
},
|
||||
});
|
||||
@@ -245,13 +247,13 @@ describe('StackRouter', () => {
|
||||
const path = 'fo/22/b/hello';
|
||||
const action = TestStackRouter.getActionForPathAndParams(path);
|
||||
expect(action).toEqual({
|
||||
type: 'Navigate',
|
||||
type: NavigationActions.NAVIGATE,
|
||||
routeName: 'foo',
|
||||
params: {
|
||||
fooThing: '22',
|
||||
},
|
||||
action: {
|
||||
type: 'Navigate',
|
||||
type: NavigationActions.NAVIGATE,
|
||||
routeName: 'bar',
|
||||
params: {
|
||||
barThing: 'hello',
|
||||
@@ -271,7 +273,7 @@ describe('StackRouter', () => {
|
||||
screen: BarScreen,
|
||||
},
|
||||
});
|
||||
const state = router.getStateForAction({ type: 'Init' });
|
||||
const state = router.getStateForAction({ type: NavigationActions.INIT });
|
||||
expect(state).toEqual({
|
||||
index: 0,
|
||||
routes: [
|
||||
@@ -281,12 +283,12 @@ describe('StackRouter', () => {
|
||||
},
|
||||
],
|
||||
});
|
||||
const state2 = router.getStateForAction({ type: 'Navigate', routeName: 'Bar', params: { name: 'Zoom' } }, state);
|
||||
const state2 = router.getStateForAction({ type: NavigationActions.NAVIGATE, routeName: 'Bar', params: { name: 'Zoom' } }, state);
|
||||
expect(state2 && state2.index).toEqual(1);
|
||||
expect(state2 && state2.routes[1].routeName).toEqual('Bar');
|
||||
expect(state2 && state2.routes[1].params).toEqual({ name: 'Zoom' });
|
||||
expect(state2 && state2.routes.length).toEqual(2);
|
||||
const state3 = router.getStateForAction({ type: 'Back' }, state2);
|
||||
const state3 = router.getStateForAction({ type: NavigationActions.BACK }, state2);
|
||||
expect(state3).toEqual({
|
||||
index: 0,
|
||||
routes: [
|
||||
@@ -314,7 +316,7 @@ describe('StackRouter', () => {
|
||||
screen: BarScreen,
|
||||
},
|
||||
});
|
||||
const state = router.getStateForAction({ type: 'Init' });
|
||||
const state = router.getStateForAction({ type: NavigationActions.INIT });
|
||||
expect(state).toEqual({
|
||||
index: 0,
|
||||
routes: [
|
||||
@@ -324,12 +326,12 @@ describe('StackRouter', () => {
|
||||
},
|
||||
],
|
||||
});
|
||||
const state2 = router.getStateForAction({ type: 'Navigate', routeName: 'Bar', params: { name: 'Zoom' } }, state);
|
||||
const state2 = router.getStateForAction({ type: NavigationActions.NAVIGATE, routeName: 'Bar', params: { name: 'Zoom' } }, state);
|
||||
expect(state2 && state2.index).toEqual(1);
|
||||
expect(state2 && state2.routes[1].routeName).toEqual('Bar');
|
||||
expect(state2 && state2.routes[1].params).toEqual({ name: 'Zoom' });
|
||||
expect(state2 && state2.routes.length).toEqual(2);
|
||||
const state3 = router.getStateForAction({ type: 'Back' }, state2);
|
||||
const state3 = router.getStateForAction({ type: NavigationActions.BACK }, state2);
|
||||
expect(state3).toEqual({
|
||||
index: 0,
|
||||
routes: [
|
||||
@@ -352,12 +354,12 @@ describe('StackRouter', () => {
|
||||
screen: BarScreen,
|
||||
},
|
||||
});
|
||||
const state = router.getStateForAction({ type: 'Init' });
|
||||
const state2 = router.getStateForAction({ type: 'Navigate', routeName: 'Bar', params: { name: 'Zoom' } }, state);
|
||||
const state3 = router.getStateForAction({ type: 'Navigate', routeName: 'Bar', params: { name: 'Foo' } }, state2);
|
||||
const state4 = router.getStateForAction({ type: 'Back', key: 'wrongKey' }, state3);
|
||||
const state = router.getStateForAction({ type: NavigationActions.INIT });
|
||||
const state2 = router.getStateForAction({ type: NavigationActions.NAVIGATE, routeName: 'Bar', params: { name: 'Zoom' } }, state);
|
||||
const state3 = router.getStateForAction({ type: NavigationActions.NAVIGATE, routeName: 'Bar', params: { name: 'Foo' } }, state2);
|
||||
const state4 = router.getStateForAction({ type: NavigationActions.BACK, key: 'wrongKey' }, state3);
|
||||
expect(state3).toEqual(state4);
|
||||
const state5 = router.getStateForAction({ type: 'Back', key: state3.routes[1].key }, state4);
|
||||
const state5 = router.getStateForAction({ type: NavigationActions.BACK, key: state3.routes[1].key }, state4);
|
||||
expect(state5).toEqual(state);
|
||||
});
|
||||
|
||||
@@ -372,7 +374,7 @@ describe('StackRouter', () => {
|
||||
screen: BarScreen,
|
||||
},
|
||||
}, { initialRouteName: 'Bar' });
|
||||
const state = router.getStateForAction({ type: 'Init' });
|
||||
const state = router.getStateForAction({ type: NavigationActions.INIT });
|
||||
expect(state).toEqual({
|
||||
index: 0,
|
||||
routes: [
|
||||
@@ -395,8 +397,8 @@ describe('StackRouter', () => {
|
||||
screen: BarScreen,
|
||||
},
|
||||
});
|
||||
const state = router.getStateForAction({ type: 'Init' });
|
||||
const state2 = router.getStateForAction({ type: 'Navigate', routeName: 'Bar', params: { bar: '42' } }, state);
|
||||
const state = router.getStateForAction({ type: NavigationActions.INIT });
|
||||
const state2 = router.getStateForAction({ type: NavigationActions.NAVIGATE, routeName: 'Bar', params: { bar: '42' } }, state);
|
||||
expect(state2).not.toBeNull();
|
||||
expect(state2 && state2.index).toEqual(1);
|
||||
expect(state2 && state2.routes[1].params).toEqual({ bar: '42' });
|
||||
@@ -414,9 +416,9 @@ describe('StackRouter', () => {
|
||||
initialRouteName: 'Bar',
|
||||
initialRouteParams: { name: 'Zoo' },
|
||||
});
|
||||
const state = router.getStateForAction({ type: 'Init' });
|
||||
const state = router.getStateForAction({ type: NavigationActions.INIT });
|
||||
const state2 = router.getStateForAction({
|
||||
type: 'SetParams',
|
||||
type: NavigationActions.SET_PARAMS,
|
||||
params: { name: 'Qux' },
|
||||
key: 'Init',
|
||||
}, state);
|
||||
@@ -433,8 +435,8 @@ describe('StackRouter', () => {
|
||||
screen: () => <div />,
|
||||
},
|
||||
});
|
||||
const state = router.getStateForAction({ type: 'Init' });
|
||||
const state2 = router.getStateForAction({ type: 'Reset', actions: [{ type: 'Navigate', routeName: 'Foo', params: { bar: '42' } }, { type: 'Navigate', routeName: 'Bar' }], index: 1 }, state);
|
||||
const state = router.getStateForAction({ type: NavigationActions.INIT });
|
||||
const state2 = router.getStateForAction({ type: NavigationActions.RESET, actions: [{ type: NavigationActions.NAVIGATE, routeName: 'Foo', params: { bar: '42' } }, { type: NavigationActions.NAVIGATE, routeName: 'Bar' }], index: 1 }, state);
|
||||
expect(state2 && state2.index).toEqual(1);
|
||||
expect(state2 && state2.routes[0].params).toEqual({ bar: '42' });
|
||||
expect(state2 && state2.routes[0].routeName).toEqual('Foo');
|
||||
@@ -459,8 +461,8 @@ describe('StackRouter', () => {
|
||||
screen: () => <div />,
|
||||
},
|
||||
});
|
||||
const state = router.getStateForAction({ type: 'Init' });
|
||||
const state2 = router.getStateForAction({ type: 'Reset', actions: [{ type: 'Navigate', routeName: 'Foo' }], index: 0 }, state);
|
||||
const state = router.getStateForAction({ type: NavigationActions.INIT });
|
||||
const state2 = router.getStateForAction({ type: NavigationActions.RESET, actions: [{ type: NavigationActions.NAVIGATE, routeName: 'Foo' }], index: 0 }, state);
|
||||
|
||||
expect(state2 && state2.index).toEqual(0);
|
||||
expect(state2 && state2.routes[0].routeName).toEqual('Foo');
|
||||
@@ -477,7 +479,7 @@ describe('StackRouter', () => {
|
||||
},
|
||||
}, { initialRouteName: 'Bar' });
|
||||
const action = router.getActionForPathAndParams('');
|
||||
expect(action).toEqual({ type: 'Navigate', routeName: 'Bar' });
|
||||
expect(action).toEqual({ type: NavigationActions.NAVIGATE, routeName: 'Bar' });
|
||||
let state = null;
|
||||
if (action) {
|
||||
state = router.getStateForAction(action);
|
||||
@@ -485,4 +487,21 @@ describe('StackRouter', () => {
|
||||
expect(state && state.index).toEqual(0);
|
||||
expect(state && state.routes[0]).toEqual({ key: 'Init', routeName: 'Bar' });
|
||||
});
|
||||
|
||||
test('Maps old actions (uses "Handles the reset action" test)', () => {
|
||||
const router = StackRouter({
|
||||
Foo: {
|
||||
screen: () => <div />,
|
||||
},
|
||||
Bar: {
|
||||
screen: () => <div />,
|
||||
},
|
||||
});
|
||||
const state = router.getStateForAction({ type: 'Init' });
|
||||
const state2 = router.getStateForAction({ type: 'Reset', actions: [{ type: 'Navigate', routeName: 'Foo', params: { bar: '42' } }, { type: 'Navigate', routeName: 'Bar' }], index: 1 }, state);
|
||||
expect(state2 && state2.index).toEqual(1);
|
||||
expect(state2 && state2.routes[0].params).toEqual({ bar: '42' });
|
||||
expect(state2 && state2.routes[0].routeName).toEqual('Foo');
|
||||
expect(state2 && state2.routes[1].routeName).toEqual('Bar');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
import React from 'react';
|
||||
import TabRouter from '../TabRouter';
|
||||
|
||||
const INIT_ACTION = { type: 'Init' };
|
||||
import NavigationActions from '../../NavigationActions';
|
||||
|
||||
const INIT_ACTION = { type: NavigationActions.INIT };
|
||||
|
||||
const BareLeafRouteConfig = {
|
||||
screen: () => <div />,
|
||||
@@ -19,13 +21,13 @@ describe('TabRouter', () => {
|
||||
Foo: { screen: ScreenA },
|
||||
Bar: { screen: ScreenB },
|
||||
});
|
||||
const state = router.getStateForAction({ type: 'Init' });
|
||||
const state = router.getStateForAction({ type: NavigationActions.INIT });
|
||||
const expectedState = {
|
||||
index: 0,
|
||||
routes: [{ key: 'Foo', routeName: 'Foo' }, { key: 'Bar', routeName: 'Bar' }],
|
||||
};
|
||||
expect(state).toEqual(expectedState);
|
||||
const state2 = router.getStateForAction({ type: 'Navigate', routeName: 'Bar' }, state);
|
||||
const state2 = router.getStateForAction({ type: NavigationActions.NAVIGATE, routeName: 'Bar' }, state);
|
||||
const expectedState2 = {
|
||||
index: 1,
|
||||
routes: [{ key: 'Foo', routeName: 'Foo' }, { key: 'Bar', routeName: 'Bar' }],
|
||||
@@ -33,7 +35,7 @@ describe('TabRouter', () => {
|
||||
expect(state2).toEqual(expectedState2);
|
||||
expect(router.getComponentForState(expectedState)).toEqual(ScreenA);
|
||||
expect(router.getComponentForState(expectedState2)).toEqual(ScreenB);
|
||||
const state3 = router.getStateForAction({ type: 'Navigate', routeName: 'Bar' }, state2);
|
||||
const state3 = router.getStateForAction({ type: NavigationActions.NAVIGATE, routeName: 'Bar' }, state2);
|
||||
expect(state3).toEqual(null);
|
||||
});
|
||||
|
||||
@@ -44,13 +46,13 @@ describe('TabRouter', () => {
|
||||
Foo: { getScreen: () => ScreenA },
|
||||
Bar: { getScreen: () => ScreenB },
|
||||
});
|
||||
const state = router.getStateForAction({ type: 'Init' });
|
||||
const state = router.getStateForAction({ type: NavigationActions.INIT });
|
||||
const expectedState = {
|
||||
index: 0,
|
||||
routes: [{ key: 'Foo', routeName: 'Foo' }, { key: 'Bar', routeName: 'Bar' }],
|
||||
};
|
||||
expect(state).toEqual(expectedState);
|
||||
const state2 = router.getStateForAction({ type: 'Navigate', routeName: 'Bar' }, state);
|
||||
const state2 = router.getStateForAction({ type: NavigationActions.NAVIGATE, routeName: 'Bar' }, state);
|
||||
const expectedState2 = {
|
||||
index: 1,
|
||||
routes: [{ key: 'Foo', routeName: 'Foo' }, { key: 'Bar', routeName: 'Bar' }],
|
||||
@@ -58,13 +60,13 @@ describe('TabRouter', () => {
|
||||
expect(state2).toEqual(expectedState2);
|
||||
expect(router.getComponentForState(expectedState)).toEqual(ScreenA);
|
||||
expect(router.getComponentForState(expectedState2)).toEqual(ScreenB);
|
||||
const state3 = router.getStateForAction({ type: 'Navigate', routeName: 'Bar' }, state2);
|
||||
const state3 = router.getStateForAction({ type: NavigationActions.NAVIGATE, routeName: 'Bar' }, state2);
|
||||
expect(state3).toEqual(null);
|
||||
});
|
||||
|
||||
test('Can set the initial tab', () => {
|
||||
const router = TabRouter({ Foo: BareLeafRouteConfig, Bar: BareLeafRouteConfig }, { initialRouteName: 'Bar' });
|
||||
const state = router.getStateForAction({ type: 'Init' });
|
||||
const state = router.getStateForAction({ type: NavigationActions.INIT });
|
||||
expect(state).toEqual({
|
||||
index: 1,
|
||||
routes: [{ key: 'Foo', routeName: 'Foo' }, { key: 'Bar', routeName: 'Bar' }],
|
||||
@@ -73,14 +75,14 @@ describe('TabRouter', () => {
|
||||
|
||||
test('getStateForAction returns null when navigating to same tab', () => {
|
||||
const router = TabRouter({ Foo: BareLeafRouteConfig, Bar: BareLeafRouteConfig }, { initialRouteName: 'Bar' });
|
||||
const state = router.getStateForAction({ type: 'Init' });
|
||||
const state2 = router.getStateForAction({ type: 'Navigate', routeName: 'Bar' }, state);
|
||||
const state = router.getStateForAction({ type: NavigationActions.INIT });
|
||||
const state2 = router.getStateForAction({ type: NavigationActions.NAVIGATE, routeName: 'Bar' }, state);
|
||||
expect(state2).toEqual(null);
|
||||
});
|
||||
|
||||
test('getStateForAction returns initial navigate', () => {
|
||||
const router = TabRouter({ Foo: BareLeafRouteConfig, Bar: BareLeafRouteConfig });
|
||||
const state = router.getStateForAction({ type: 'Navigate', routeName: 'Foo' });
|
||||
const state = router.getStateForAction({ type: NavigationActions.NAVIGATE, routeName: 'Foo' });
|
||||
expect(state && state.index).toEqual(0);
|
||||
});
|
||||
|
||||
@@ -89,7 +91,7 @@ describe('TabRouter', () => {
|
||||
ChildTabNavigator.router = TabRouter({ Foo: BareLeafRouteConfig, Bar: BareLeafRouteConfig });
|
||||
const router = TabRouter({ Foo: BareLeafRouteConfig, Baz: { screen: ChildTabNavigator }, Boo: BareLeafRouteConfig });
|
||||
const action = router.getActionForPathAndParams('Baz/Bar', { foo: '42' });
|
||||
const navAction = { type: 'Navigate', routeName: 'Baz', action: { type: 'Navigate', routeName: 'Bar', params: { foo: '42' } } };
|
||||
const navAction = { type: NavigationActions.NAVIGATE, routeName: 'Baz', action: { type: NavigationActions.NAVIGATE, routeName: 'Bar', params: { foo: '42' } } };
|
||||
expect(action).toEqual(navAction);
|
||||
const state = router.getStateForAction(navAction);
|
||||
expect(state).toEqual({
|
||||
@@ -126,7 +128,7 @@ describe('TabRouter', () => {
|
||||
const ChildTabNavigator = () => <div />;
|
||||
ChildTabNavigator.router = TabRouter({ Foo: BareLeafRouteConfig, Bar: BareLeafRouteConfig });
|
||||
const router = TabRouter({ Foo: BareLeafRouteConfig, Baz: { screen: ChildTabNavigator }, Boo: BareLeafRouteConfig });
|
||||
const state = router.getStateForAction({ type: 'Navigate', routeName: 'Bar' });
|
||||
const state = router.getStateForAction({ type: NavigationActions.NAVIGATE, routeName: 'Bar' });
|
||||
expect(state).toEqual({
|
||||
index: 1,
|
||||
routes: [
|
||||
@@ -143,7 +145,7 @@ describe('TabRouter', () => {
|
||||
{ key: 'Boo', routeName: 'Boo' },
|
||||
],
|
||||
});
|
||||
const state2 = router.getStateForAction({ type: 'Navigate', routeName: 'Foo' }, state);
|
||||
const state2 = router.getStateForAction({ type: NavigationActions.NAVIGATE, routeName: 'Foo' }, state);
|
||||
expect(state2).toEqual({
|
||||
index: 1,
|
||||
routes: [
|
||||
@@ -160,7 +162,7 @@ describe('TabRouter', () => {
|
||||
{ key: 'Boo', routeName: 'Boo' },
|
||||
],
|
||||
});
|
||||
const state3 = router.getStateForAction({ type: 'Navigate', routeName: 'Foo' }, state2);
|
||||
const state3 = router.getStateForAction({ type: NavigationActions.NAVIGATE, routeName: 'Foo' }, state2);
|
||||
expect(state3).toEqual(null);
|
||||
});
|
||||
|
||||
@@ -198,7 +200,7 @@ describe('TabRouter', () => {
|
||||
{ key: 'Gah', routeName: 'Gah' },
|
||||
],
|
||||
});
|
||||
const state2 = router.getStateForAction({ type: 'Navigate', routeName: 'Zap' }, state);
|
||||
const state2 = router.getStateForAction({ type: NavigationActions.NAVIGATE, routeName: 'Zap' }, state);
|
||||
expect(state2).toEqual({
|
||||
index: 0,
|
||||
routes: [
|
||||
@@ -224,9 +226,9 @@ describe('TabRouter', () => {
|
||||
{ key: 'Gah', routeName: 'Gah' },
|
||||
],
|
||||
});
|
||||
const state3 = router.getStateForAction({ type: 'Navigate', routeName: 'Zap' }, state2);
|
||||
const state3 = router.getStateForAction({ type: NavigationActions.NAVIGATE, routeName: 'Zap' }, state2);
|
||||
expect(state3).toEqual(null);
|
||||
const state4 = router.getStateForAction({ type: 'Navigate', routeName: 'Foo', action: { type: 'Navigate', routeName: 'Bar', action: { type: 'Navigate', routeName: 'Zap' } } });
|
||||
const state4 = router.getStateForAction({ type: NavigationActions.NAVIGATE, routeName: 'Foo', action: { type: NavigationActions.NAVIGATE, routeName: 'Bar', action: { type: NavigationActions.NAVIGATE, routeName: 'Zap' } } });
|
||||
expect(state4).toEqual({
|
||||
index: 0,
|
||||
routes: [
|
||||
@@ -274,11 +276,11 @@ describe('TabRouter', () => {
|
||||
foo: '42',
|
||||
},
|
||||
routeName: 'Bar',
|
||||
type: 'Navigate',
|
||||
type: NavigationActions.NAVIGATE,
|
||||
};
|
||||
expect(action).toEqual(expectedAction);
|
||||
|
||||
const state = router.getStateForAction({ type: 'Init' });
|
||||
const state = router.getStateForAction({ type: NavigationActions.INIT });
|
||||
const expectedState = {
|
||||
index: 0,
|
||||
routes: [{ key: 'Foo', routeName: 'Foo' }, { key: 'Bar', routeName: 'Bar' }],
|
||||
@@ -315,7 +317,7 @@ describe('TabRouter', () => {
|
||||
foo: '42',
|
||||
},
|
||||
routeName: 'Foo',
|
||||
type: 'Navigate',
|
||||
type: NavigationActions.NAVIGATE,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -355,4 +357,11 @@ describe('TabRouter', () => {
|
||||
const { path } = router.getPathAndParamsForState(state);
|
||||
expect(path).toEqual('f/Baz');
|
||||
});
|
||||
|
||||
test('Maps old actions (uses "getStateForAction returns null when navigating to same tab" test)', () => {
|
||||
const router = TabRouter({ Foo: BareLeafRouteConfig, Bar: BareLeafRouteConfig }, { initialRouteName: 'Bar' });
|
||||
const state = router.getStateForAction({ type: 'Init' });
|
||||
const state2 = router.getStateForAction({ type: 'Navigate', routeName: 'Bar' }, state);
|
||||
expect(state2).toEqual(null);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,6 +14,7 @@ import CardStackStyleInterpolator from './CardStackStyleInterpolator';
|
||||
import CardStackPanResponder from './CardStackPanResponder';
|
||||
import Header from './Header';
|
||||
import NavigationPropTypes from '../PropTypes';
|
||||
import NavigationActions from '../NavigationActions';
|
||||
import addNavigationHelpers from '../addNavigationHelpers';
|
||||
import SceneView from './SceneView';
|
||||
|
||||
@@ -120,8 +121,8 @@ class CardStack extends React.Component<DefaultProps, Props, void> {
|
||||
|
||||
/**
|
||||
* The navigation prop, including the state and the dispatcher for the back
|
||||
* action. The dispatcher must handle the back action ({type: 'Back'}), and
|
||||
* the navigation state has this shape:
|
||||
* action. The dispatcher must handle the back action
|
||||
* ({ type: NavigationActions.BACK }), and the navigation state has this shape:
|
||||
*
|
||||
* ```js
|
||||
* const navigationState = {
|
||||
@@ -338,7 +339,7 @@ class CardStack extends React.Component<DefaultProps, Props, void> {
|
||||
if (this.props.gesturesEnabled) {
|
||||
let onNavigateBack = null;
|
||||
if (this.props.navigation.state.index !== 0) {
|
||||
onNavigateBack = () => this.props.navigation.dispatch({ type: 'Back', key: props.scene.route.key });
|
||||
onNavigateBack = () => this.props.navigation.dispatch(NavigationActions.back({ key: props.scene.route.key }));
|
||||
}
|
||||
const panHandlersProps = {
|
||||
...props,
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { addNavigationHelpers } from 'react-navigation';
|
||||
import { NavigationActions, addNavigationHelpers } from 'react-navigation';
|
||||
|
||||
function getAction(router, path, params) {
|
||||
const action = router.getActionForPathAndParams(path, params);
|
||||
if (action) {
|
||||
return action;
|
||||
}
|
||||
return {
|
||||
return NavigationActions.navigate({
|
||||
params: { path },
|
||||
routeName: 'NotFound',
|
||||
type: 'Navigate',
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = (NavigationAwareView) => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { PropTypes, Component } from 'react';
|
||||
import { NavigationActions } from 'react-navigation'
|
||||
|
||||
const isModifiedEvent = (event) =>
|
||||
!!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);
|
||||
@@ -17,7 +18,7 @@ const Linkable = (Inner) => {
|
||||
getAction = () => {
|
||||
const {to, href} = this.props;
|
||||
if (typeof to === 'string') {
|
||||
return { type: 'Navigate', routeName: to };
|
||||
return NavigationActions.navigate({ routeName: to });
|
||||
} else if (typeof to === 'object' && typeof to.type === 'string') {
|
||||
return to;
|
||||
} else if (href) {
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { Component } from 'react';
|
||||
|
||||
import Link from "./Link";
|
||||
|
||||
import { addNavigationHelpers } from 'react-navigation';
|
||||
import { NavigationActions, addNavigationHelpers } from 'react-navigation';
|
||||
|
||||
const LinkableLi = Link.Linkable(props => <li {...props} />);
|
||||
|
||||
@@ -22,36 +22,31 @@ class PageWithSidebar extends Component {
|
||||
let prevAction = null;
|
||||
if (state.routes[state.index].index > 0) {
|
||||
const prev = state.routes[state.index].index - 1;
|
||||
prevAction = {
|
||||
type: 'Navigate',
|
||||
prevAction = NavigationActions.navigate({
|
||||
routeName: state.routes[state.index].routes[prev].routeName,
|
||||
};
|
||||
});
|
||||
}
|
||||
if (!prevAction && state.index > 0) {
|
||||
const prev = state.index - 1;
|
||||
prevAction = {
|
||||
type: 'Navigate',
|
||||
prevAction = NavigationActions.navigate({
|
||||
routeName: state.routes[prev].routeName,
|
||||
action: {
|
||||
type: 'Navigate',
|
||||
action: NavigationActions.navigate({
|
||||
routeName: state.routes[prev].routes[state.routes[prev].routes.length - 1].routeName,
|
||||
}
|
||||
};
|
||||
})
|
||||
});
|
||||
}
|
||||
let nextAction = null;
|
||||
if (state.routes[state.index].index < state.routes[state.index].routes.length - 1) {
|
||||
const next = state.routes[state.index].index + 1;
|
||||
nextAction = {
|
||||
type: 'Navigate',
|
||||
nextAction = NavigationActions.navigate({
|
||||
routeName: state.routes[state.index].routes[next].routeName,
|
||||
};
|
||||
});
|
||||
}
|
||||
if (!nextAction && state.index < state.routes.length - 1) {
|
||||
const next = state.index + 1;
|
||||
nextAction = {
|
||||
type: 'Navigate',
|
||||
nextAction = NavigationActions.navigate({
|
||||
routeName: state.routes[next].routeName,
|
||||
};
|
||||
});
|
||||
}
|
||||
let prevName = prevAction && getConfig(router, state, prevAction, 'linkName');
|
||||
let nextName = nextAction && getConfig(router, state, nextAction, 'linkName');
|
||||
|
||||
@@ -10,7 +10,7 @@ const ReactDOMServer = require('react-dom/server');
|
||||
|
||||
import App from './App';
|
||||
|
||||
import { addNavigationHelpers } from 'react-navigation';
|
||||
import { NavigationActions, addNavigationHelpers } from 'react-navigation';
|
||||
|
||||
class ServerApp extends React.Component {
|
||||
static childContextTypes = {
|
||||
@@ -41,7 +41,7 @@ function AppHandler(req, res) {
|
||||
const path = req.url.substr(1)
|
||||
let initAction = App.router.getActionForPathAndParams(path);
|
||||
if (!initAction) {
|
||||
initAction = { type: 'Navigate', routeName: 'NotFound', params: { path } };
|
||||
initAction = NavigationActions.navigate({ routeName: 'NotFound', params: { path } });
|
||||
status = 404;
|
||||
}
|
||||
const topNavigation = addNavigationHelpers({
|
||||
|
||||
Reference in New Issue
Block a user