diff --git a/examples/NavigationPlayground/yarn.lock b/examples/NavigationPlayground/yarn.lock
index e7d2c50c..7f2be235 100644
--- a/examples/NavigationPlayground/yarn.lock
+++ b/examples/NavigationPlayground/yarn.lock
@@ -1659,6 +1659,13 @@ create-react-class@^15.5.2:
loose-envify "^1.3.1"
object-assign "^4.1.1"
+create-react-context@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/create-react-context/-/create-react-context-0.2.1.tgz#425a3d96f4b7690c2fbf20aed5aeae2e2007a959"
+ dependencies:
+ fbjs "^0.8.0"
+ gud "^1.0.0"
+
cross-spawn@^5.0.1, cross-spawn@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
@@ -2247,7 +2254,7 @@ fbjs-scripts@^0.8.1:
semver "^5.1.0"
through2 "^2.0.0"
-fbjs@^0.8.14, fbjs@^0.8.16, fbjs@^0.8.4, fbjs@^0.8.9:
+fbjs@^0.8.0, fbjs@^0.8.14, fbjs@^0.8.16, fbjs@^0.8.4, fbjs@^0.8.9:
version "0.8.16"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db"
dependencies:
@@ -2625,6 +2632,10 @@ growly@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
+gud@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0"
+
gulp-util@^3.0.4:
version "3.0.8"
resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-3.0.8.tgz#0054e1e744502e27c04c187c3ecc505dd54bbb4f"
diff --git a/package.json b/package.json
index a695229c..9d7a37cc 100644
--- a/package.json
+++ b/package.json
@@ -30,6 +30,7 @@
},
"dependencies": {
"clamp": "^1.0.1",
+ "create-react-context": "^0.2.1",
"hoist-non-react-statics": "^2.2.0",
"path-to-regexp": "^1.7.0",
"prop-types": "^15.5.10",
diff --git a/src/navigators/__tests__/StackNavigator-test.js b/src/navigators/__tests__/StackNavigator-test.js
index 24933224..0c3bfeea 100644
--- a/src/navigators/__tests__/StackNavigator-test.js
+++ b/src/navigators/__tests__/StackNavigator-test.js
@@ -3,6 +3,7 @@ import { StyleSheet, View } from 'react-native';
import renderer from 'react-test-renderer';
import StackNavigator from '../createStackNavigator';
+import withNavigation from '../../views/withNavigation';
const styles = StyleSheet.create({
header: {
@@ -51,4 +52,37 @@ describe('StackNavigator', () => {
expect(rendered).toMatchSnapshot();
});
+
+ it('passes navigation to headerRight when wrapped in withNavigation', () => {
+ const spy = jest.fn();
+
+ class TestComponent extends React.Component {
+ render() {
+ return {this.props.onPress(this.props.navigation)};
+ }
+ }
+
+ const TestComponentWithNavigation = withNavigation(TestComponent);
+
+ class A extends React.Component {
+ static navigationOptions = {
+ headerRight: ,
+ };
+
+ render() {
+ return ;
+ }
+ }
+
+ const Nav = StackNavigator({ A: { screen: A } });
+
+ renderer.create();
+
+ expect(spy).toBeCalledWith(
+ expect.objectContaining({
+ navigate: expect.any(Function),
+ addListener: expect.any(Function),
+ })
+ );
+ });
});
diff --git a/src/views/NavigationContext.js b/src/views/NavigationContext.js
new file mode 100644
index 00000000..1c8c81ea
--- /dev/null
+++ b/src/views/NavigationContext.js
@@ -0,0 +1,8 @@
+import React from 'react';
+import propTypes from 'prop-types';
+import createReactContext from 'create-react-context';
+
+const NavigationContext = createReactContext();
+
+export const NavigationProvider = NavigationContext.Provider;
+export const NavigationConsumer = NavigationContext.Consumer;
diff --git a/src/views/SceneView.js b/src/views/SceneView.js
index 01710bcc..de68dc0b 100644
--- a/src/views/SceneView.js
+++ b/src/views/SceneView.js
@@ -1,19 +1,14 @@
import React from 'react';
import propTypes from 'prop-types';
+import { NavigationProvider } from './NavigationContext';
export default class SceneView extends React.PureComponent {
- static childContextTypes = {
- navigation: propTypes.object.isRequired,
- };
-
- getChildContext() {
- return {
- navigation: this.props.navigation,
- };
- }
-
render() {
- const { screenProps, navigation, component: Component } = this.props;
- return ;
+ const { screenProps, component: Component, navigation } = this.props;
+ return (
+
+
+
+ );
}
}
diff --git a/src/views/StackView/StackViewLayout.js b/src/views/StackView/StackViewLayout.js
index 12bb5ec6..1d2f50e3 100644
--- a/src/views/StackView/StackViewLayout.js
+++ b/src/views/StackView/StackViewLayout.js
@@ -15,6 +15,7 @@ import Card from './StackViewCard';
import Header from '../Header/Header';
import NavigationActions from '../../NavigationActions';
import SceneView from '../SceneView';
+import { NavigationProvider } from '../NavigationContext';
import TransitionConfigs from './StackViewTransitionConfigs';
import * as ReactNativeFeatures from '../../utils/ReactNativeFeatures';
@@ -194,9 +195,11 @@ class StackViewLayout extends React.Component {
let floatingHeader = null;
const headerMode = this._getHeaderMode();
if (headerMode === 'float') {
- floatingHeader = this._renderHeader(
- this.props.transitionProps.scene,
- headerMode
+ const { scene } = this.props.transitionProps;
+ floatingHeader = (
+
+ {this._renderHeader(scene, headerMode)}
+
);
}
const {
diff --git a/src/views/withNavigation.js b/src/views/withNavigation.js
index bddfb646..c2fe0085 100644
--- a/src/views/withNavigation.js
+++ b/src/views/withNavigation.js
@@ -1,24 +1,31 @@
import React from 'react';
import propTypes from 'prop-types';
import hoistStatics from 'hoist-non-react-statics';
+import invariant from '../utils/invariant';
+import { NavigationConsumer } from './NavigationContext';
export default function withNavigation(Component) {
class ComponentWithNavigation extends React.Component {
static displayName = `withNavigation(${Component.displayName ||
Component.name})`;
- static contextTypes = {
- navigation: propTypes.object.isRequired,
- };
-
render() {
- const { navigation } = this.context;
return (
-
+
+ {navigation => {
+ invariant(
+ !!navigation,
+ 'withNavigationFocus can only be used on a view hierarchy of a navigator. The wrapped component is unable to get access to navigation from props or context.'
+ );
+ return (
+
+ );
+ }}
+
);
}
}
diff --git a/src/views/withNavigationFocus.js b/src/views/withNavigationFocus.js
index 98eb3d5d..e4f88378 100644
--- a/src/views/withNavigationFocus.js
+++ b/src/views/withNavigationFocus.js
@@ -2,26 +2,28 @@ import React from 'react';
import propTypes from 'prop-types';
import hoistStatics from 'hoist-non-react-statics';
import invariant from '../utils/invariant';
+import withNavigation from './withNavigation';
export default function withNavigationFocus(Component) {
class ComponentWithNavigationFocus extends React.Component {
static displayName = `withNavigationFocus(${Component.displayName ||
Component.name})`;
- static contextTypes = {
- navigation: propTypes.object.isRequired,
- };
-
- constructor(props, context) {
- super();
+ constructor(props) {
+ super(props);
this.state = {
- isFocused: this.getNavigation(props, context).isFocused(),
+ isFocused: props.navigation ? props.navigation.isFocused() : false,
};
}
componentDidMount() {
- const navigation = this.getNavigation();
+ const { navigation } = this.props;
+ invariant(
+ !!navigation,
+ 'withNavigationFocus can only be used on a view hierarchy of a navigator. The wrapped component is unable to get access to navigation from props or context.'
+ );
+
this.subscriptions = [
navigation.addListener('didFocus', () =>
this.setState({ isFocused: true })
@@ -36,15 +38,6 @@ export default function withNavigationFocus(Component) {
this.subscriptions.forEach(sub => sub.remove());
}
- getNavigation = (props = this.props, context = this.context) => {
- const navigation = props.navigation || context.navigation;
- invariant(
- !!navigation,
- 'withNavigationFocus can only be used on a view hierarchy of a navigator. The wrapped component is unable to get access to navigation from props or context.'
- );
- return navigation;
- };
-
render() {
return (