Compare commits

...

6 Commits

Author SHA1 Message Date
Eric Vicenti
655453aed3 reactotron hello world 2018-07-12 11:28:46 -07:00
Eric Vicenti
c4b84f1d66 Fix container referene to startup state data 2018-07-12 11:01:11 -07:00
Michael Lefkowitz
69f394be5b Feat/allow keyless replace (#4636)
* allow key to be undefined on StackNavigation.replace method

* added tests for replace action w/out key

* fix typo

* updated changelog

* updated teests for clarity

* added length check on routes to safely fallthrough to search
2018-07-10 23:41:42 -07:00
Eric Vicenti
316e4991ac Add enableURLHandling to navigation container 2018-07-10 14:47:57 -07:00
Ashoat Tevosyan
805064cb5e [flow] Make NavigationRoute types exact (#4667)
React Native 0.56 introduces Flow 0.75, which makes it impossible to refine `NavigationRoute` based on the presence of `index` or `routes` properties.

This PR turns `NavigationStateRoute` and `NavigationLeafRoute` into exact types, which addresses this issue.
2018-07-10 13:59:09 -07:00
Dariusz Łuksza
8f199980cb Fix changelog (#4651)
Fixes 2.6.1 header link
2018-07-06 20:21:00 -07:00
8 changed files with 157 additions and 18 deletions

View File

@@ -6,12 +6,14 @@ 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-05)(https://github.com/react-navigation/react-navigation/releases/tag/2.6.2)
## [2.6.2] - [2018-07-06](https://github.com/react-navigation/react-navigation/releases/tag/2.6.2)
### Changed
- Relax vertical padding warnings on header.
## [2.6.1] - [2018-07-05)(https://github.com/react-navigation/react-navigation/releases/tag/2.6.1)
## [2.6.1] - [2018-07-05](https://github.com/react-navigation/react-navigation/releases/tag/2.6.1)
### Added
- Warn for more invalid headerStyle properties (padding, top/right/bottom/left, position).

View File

@@ -16,6 +16,9 @@ import {
StatusBar,
View,
} from 'react-native';
import Reactotron from 'reactotron-react-native';
import { SafeAreaView, createStackNavigator } from 'react-navigation';
import CustomTabs from './CustomTabs';
@@ -39,6 +42,11 @@ import TabsWithNavigationFocus from './TabsWithNavigationFocus';
import TabsWithNavigationEvents from './TabsWithNavigationEvents';
import KeyboardHandlingExample from './KeyboardHandlingExample';
Reactotron.configure()
.useReactNative()
.connect();
console.tron = Reactotron;
const ExampleInfo = {
SimpleStack: {
name: 'Stack Example',
@@ -340,7 +348,9 @@ const AppNavigator = createStackNavigator(
}
);
export default AppNavigator;
const App = () => <AppNavigator persistenceKey="yes" />;
export default App;
const styles = StyleSheet.create({
item: {

View File

@@ -19,7 +19,8 @@
"react-navigation": "link:../..",
"react-navigation-header-buttons": "^0.0.4",
"react-navigation-material-bottom-tabs": "0.1.3",
"react-navigation-tabs": "^0.5.1"
"react-navigation-tabs": "^0.5.1",
"reactotron-react-native": "^2.0.0"
},
"devDependencies": {
"babel-jest": "^22.4.1",

View File

@@ -4734,6 +4734,10 @@ minizlib@^1.1.0:
dependencies:
minipass "^2.2.1"
mitt@^1.1.2:
version "1.1.3"
resolved "https://registry.yarnpkg.com/mitt/-/mitt-1.1.3.tgz#528c506238a05dce11cd914a741ea2cc332da9b8"
mixin-deep@^1.2.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe"
@@ -5446,6 +5450,13 @@ qs@6.5.2, qs@^6.4.0, qs@^6.5.0, qs@^6.5.1, qs@~6.5.1:
version "6.5.2"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
query-string@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.1.0.tgz#01e7d69f6a0940dac67a937d6c6325647aa4532a"
dependencies:
decode-uri-component "^0.2.0"
strict-uri-encode "^2.0.0"
querystring@0.2.0, querystring@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
@@ -5758,9 +5769,9 @@ react-navigation-deprecated-tab-navigator@1.3.0:
dependencies:
react-native-tab-view "^0.0.77"
react-navigation-drawer@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/react-navigation-drawer/-/react-navigation-drawer-0.3.0.tgz#641007213f0f1e1b55a0a4bb64d71df07b3e7208"
react-navigation-drawer@0.4.3:
version "0.4.3"
resolved "https://registry.yarnpkg.com/react-navigation-drawer/-/react-navigation-drawer-0.4.3.tgz#c04c94e2429b7e724801af05bd0a93a79cb27f71"
dependencies:
react-native-drawer-layout-polyfill "^1.3.2"
@@ -5871,6 +5882,18 @@ react@^16.0.0:
object-assign "^4.1.1"
prop-types "^15.6.0"
reactotron-core-client@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/reactotron-core-client/-/reactotron-core-client-2.0.0.tgz#0229e7938ed17104b846c50295ae8cb40557e83c"
reactotron-react-native@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/reactotron-react-native/-/reactotron-react-native-2.0.0.tgz#54d1119c6640b7e8c6c7383e482474d4cef11016"
dependencies:
mitt "^1.1.2"
prop-types "^15.5.10"
reactotron-core-client "^2.0.0"
read-chunk@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/read-chunk/-/read-chunk-2.1.0.tgz#6a04c0928005ed9d42e1a6ac5600e19cbc7ff655"
@@ -6570,6 +6593,10 @@ stream-parser@~0.3.1:
dependencies:
debug "2"
strict-uri-encode@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
string-length@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed"

View File

@@ -184,7 +184,7 @@ declare module 'react-navigation' {
| NavigationLeafRoute
| NavigationStateRoute;
declare export type NavigationLeafRoute = {
declare export type NavigationLeafRoute = {|
/**
* React's key used by some navigators. No need to specify these manually,
* they will be defined by the router.
@@ -204,10 +204,12 @@ declare module 'react-navigation' {
* e.g. `{ car_id: 123 }` in a route that displays a car.
*/
params?: NavigationParams,
};
|};
declare export type NavigationStateRoute = NavigationLeafRoute &
NavigationState;
declare export type NavigationStateRoute = {|
...NavigationLeafRoute,
...$Exact<NavigationState>,
|};
/**
* Router

View File

@@ -130,7 +130,11 @@ export default function createNavigationContainer(Component) {
}
_handleOpenURL = ({ url }) => {
const parsedUrl = urlToPathAndParams(url, this.props.uriPrefix);
const { enableURLHandling, uriPrefix } = this.props;
if (enableURLHandling === false) {
return;
}
const parsedUrl = urlToPathAndParams(url, uriPrefix);
if (parsedUrl) {
const { path, params } = parsedUrl;
const action = Component.router.getActionForPathAndParams(path, params);
@@ -199,11 +203,15 @@ export default function createNavigationContainer(Component) {
Linking.addEventListener('url', this._handleOpenURL);
// Pull out anything that can impact state
const { persistenceKey, uriPrefix } = this.props;
const startupStateJSON =
persistenceKey && (await AsyncStorage.getItem(persistenceKey));
const url = await Linking.getInitialURL();
const parsedUrl = url && urlToPathAndParams(url, uriPrefix);
const { persistenceKey, uriPrefix, enableURLHandling } = this.props;
let parsedUrl = null;
let startupStateJSON = null;
if (enableURLHandling !== false) {
startupStateJSON =
persistenceKey && (await AsyncStorage.getItem(persistenceKey));
const url = await Linking.getInitialURL();
parsedUrl = url && urlToPathAndParams(url, uriPrefix);
}
// Initialize state. This must be done *after* any async code
// so we don't end up with a different value for this.state.nav
@@ -257,6 +265,16 @@ export default function createNavigationContainer(Component) {
return;
}
console.tron &&
console.tron.display({
name: 'Navigation',
preview: 'Initial State',
value: {
initialState: startupState,
initialAction: this._initialAction,
},
});
this.setState({ nav: startupState }, () => {
_reactNavigationIsHydratingState = false;
dispatchActions();

View File

@@ -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];

View File

@@ -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 = () => <div />;
GrandChildNavigator.router = StackRouter({
Quux: { screen: () => <div /> },
Corge: { screen: () => <div /> },
Grault: { screen: () => <div /> },
});
const ChildNavigator = () => <div />;
ChildNavigator.router = StackRouter({
Baz: { screen: () => <div /> },
Woo: { screen: () => <div /> },
Qux: { screen: GrandChildNavigator },
});
const router = StackRouter({
Foo: { screen: () => <div /> },
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 = () => <div />;
const BarScreen = () => <div />;