[flow] Make StackRouter action creators optional and add DrawerRouter ones (#4257)

This will force all Flow users to do runtime assertions if they want to use these action creators. Open to any better solutions.
This commit is contained in:
Ashoat Tevosyan 2018-05-23 13:18:35 -04:00 committed by Brent Vatne
parent 72f17538c2
commit 046a9f8930
6 changed files with 61 additions and 35 deletions

View File

@ -16,6 +16,8 @@ import {
SafeAreaView,
withNavigation,
} from 'react-navigation';
import invariant from 'invariant';
import SampleText from './SampleText';
import { Button } from './commonComponents/ButtonWithMargin';
import { HeaderButtons } from './commonComponents/HeaderButtons';
@ -48,11 +50,16 @@ const MyBackButtonWithNavigation = withNavigation(MyBackButton);
class MyNavScreen extends React.Component<MyNavScreenProps> {
render() {
const { navigation, banner } = this.props;
const { push, replace, popToTop, pop, dismiss } = navigation;
invariant(
push && replace && popToTop && pop && dismiss,
'missing action creators for StackNavigator'
);
return (
<SafeAreaView>
<SampleText>{banner}</SampleText>
<Button
onPress={() => navigation.push('Profile', { name: 'Jane' })}
onPress={() => push('Profile', { name: 'Jane' })}
title="Push a profile screen"
/>
<Button
@ -60,13 +67,13 @@ class MyNavScreen extends React.Component<MyNavScreenProps> {
title="Navigate to a photos screen"
/>
<Button
onPress={() => navigation.replace('Profile', { name: 'Lucy' })}
onPress={() => replace('Profile', { name: 'Lucy' })}
title="Replace with profile"
/>
<Button onPress={() => navigation.popToTop()} title="Pop to top" />
<Button onPress={() => navigation.pop()} title="Pop" />
<Button onPress={() => popToTop()} title="Pop to top" />
<Button onPress={() => pop()} title="Pop" />
<Button onPress={() => navigation.goBack()} title="Go back" />
<Button onPress={() => navigation.dismiss()} title="Dismiss" />
<Button onPress={() => dismiss()} title="Dismiss" />
<StatusBar barStyle="default" />
</SafeAreaView>
);

View File

@ -6,6 +6,8 @@ import type { NavigationScreenProp } from 'react-navigation';
import * as React from 'react';
import { ScrollView, StatusBar } from 'react-native';
import { createStackNavigator, SafeAreaView } from 'react-navigation';
import invariant from 'invariant';
import { Button } from './commonComponents/ButtonWithMargin';
type NavScreenProps = {
@ -19,15 +21,14 @@ class HomeScreen extends React.Component<NavScreenProps> {
render() {
const { navigation } = this.props;
const { push } = navigation;
invariant(push, 'missing `push` action creator for StackNavigator');
return (
<SafeAreaView style={{ paddingTop: 30 }}>
<Button onPress={() => push('Other')} title="Push another screen" />
<Button
onPress={() => navigation.push('Other')}
title="Push another screen"
/>
<Button
onPress={() => navigation.push('ScreenWithNoHeader')}
onPress={() => push('ScreenWithNoHeader')}
title="Push screen with no header"
/>
<Button onPress={() => navigation.goBack(null)} title="Go Home" />
@ -44,18 +45,20 @@ class OtherScreen extends React.Component<NavScreenProps> {
render() {
const { navigation } = this.props;
const { push, pop } = navigation;
invariant(push && pop, 'missing action creators for StackNavigator');
return (
<SafeAreaView style={{ paddingTop: 30 }}>
<Button
onPress={() => navigation.push('ScreenWithLongTitle')}
onPress={() => push('ScreenWithLongTitle')}
title="Push another screen"
/>
<Button
onPress={() => navigation.push('ScreenWithNoHeader')}
onPress={() => push('ScreenWithNoHeader')}
title="Push screen with no header"
/>
<Button onPress={() => navigation.pop()} title="Pop" />
<Button onPress={() => pop()} title="Pop" />
<Button onPress={() => navigation.goBack(null)} title="Go back" />
<StatusBar barStyle="default" />
</SafeAreaView>
@ -70,10 +73,12 @@ class ScreenWithLongTitle extends React.Component<NavScreenProps> {
render() {
const { navigation } = this.props;
const { pop } = navigation;
invariant(pop, 'missing `pop` action creator for StackNavigator');
return (
<SafeAreaView style={{ paddingTop: 30 }}>
<Button onPress={() => navigation.pop()} title="Pop" />
<Button onPress={() => pop()} title="Pop" />
<Button onPress={() => navigation.goBack(null)} title="Go back" />
<StatusBar barStyle="default" />
</SafeAreaView>
@ -89,14 +94,13 @@ class ScreenWithNoHeader extends React.Component<NavScreenProps> {
render() {
const { navigation } = this.props;
const { push, pop } = navigation;
invariant(push && pop, 'missing action creators for StackNavigator');
return (
<SafeAreaView style={{ paddingTop: 30 }}>
<Button
onPress={() => navigation.push('Other')}
title="Push another screen"
/>
<Button onPress={() => navigation.pop()} title="Pop" />
<Button onPress={() => push('Other')} title="Push another screen" />
<Button onPress={() => pop()} title="Pop" />
<Button onPress={() => navigation.goBack(null)} title="Go back" />
<StatusBar barStyle="default" />
</SafeAreaView>

View File

@ -19,6 +19,8 @@ import {
View,
} from 'react-native';
import { Header, createStackNavigator } from 'react-navigation';
import invariant from 'invariant';
import SampleText from './SampleText';
import { Button } from './commonComponents/ButtonWithMargin';
import { HeaderButtons } from './commonComponents/HeaderButtons';
@ -31,11 +33,16 @@ type MyNavScreenProps = {
class MyNavScreen extends React.Component<MyNavScreenProps> {
render() {
const { navigation, banner } = this.props;
const { push, replace, popToTop, pop } = navigation;
invariant(
push && replace && popToTop && pop,
'missing action creators for StackNavigator'
);
return (
<ScrollView style={{ flex: 1 }} {...this.getHeaderInset()}>
<SampleText>{banner}</SampleText>
<Button
onPress={() => navigation.push('Profile', { name: 'Jane' })}
onPress={() => push('Profile', { name: 'Jane' })}
title="Push a profile screen"
/>
<Button
@ -43,11 +50,11 @@ class MyNavScreen extends React.Component<MyNavScreenProps> {
title="Navigate to a photos screen"
/>
<Button
onPress={() => navigation.replace('Profile', { name: 'Lucy' })}
onPress={() => replace('Profile', { name: 'Lucy' })}
title="Replace with profile"
/>
<Button onPress={() => navigation.popToTop()} title="Pop to top" />
<Button onPress={() => navigation.pop()} title="Pop" />
<Button onPress={() => popToTop()} title="Pop to top" />
<Button onPress={() => pop()} title="Pop" />
<Button onPress={() => navigation.goBack(null)} title="Go back" />
<StatusBar barStyle="default" />
</ScrollView>

View File

@ -12,6 +12,7 @@
},
"dependencies": {
"expo": "^26.0.0",
"invariant": "^2.2.4",
"react": "16.3.0-alpha.1",
"react-native": "^0.54.0",
"react-native-iphone-x-helper": "^1.0.2",

View File

@ -3424,7 +3424,7 @@ instapromise@^2.0.7:
version "2.0.7"
resolved "https://registry.yarnpkg.com/instapromise/-/instapromise-2.0.7.tgz#85e66b31021194da11214c865127ef04ec30167a"
invariant@^2.0.0, invariant@^2.2.0, invariant@^2.2.2:
invariant@^2.0.0, invariant@^2.2.0, invariant@^2.2.2, invariant@^2.2.4:
version "2.2.4"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
dependencies:

View File

@ -489,8 +489,14 @@ declare module 'react-navigation' {
declare export type NavigationScreenProp<+S> = {
+state: S,
dispatch: NavigationDispatch,
addListener: (
eventName: string,
callback: NavigationEventCallback
) => NavigationEventSubscription,
getParam: (paramName: string, fallback?: any) => any,
isFocused: () => boolean,
// Shared action creators that exist for all routers
goBack: (routeKey?: ?string) => boolean,
dismiss: () => boolean,
navigate: (
routeName:
| string
@ -504,24 +510,25 @@ declare module 'react-navigation' {
action?: NavigationNavigateAction
) => boolean,
setParams: (newParams: NavigationParams) => boolean,
getParam: (paramName: string, fallback?: any) => any,
addListener: (
eventName: string,
callback: NavigationEventCallback
) => NavigationEventSubscription,
push: (
// StackRouter action creators
pop?: (n?: number, params?: { immediate?: boolean }) => boolean,
popToTop?: (params?: { immediate?: boolean }) => boolean,
push?: (
routeName: string,
params?: NavigationParams,
action?: NavigationNavigateAction
) => boolean,
replace: (
replace?: (
routeName: string,
params?: NavigationParams,
action?: NavigationNavigateAction
) => boolean,
pop: (n?: number, params?: { immediate?: boolean }) => boolean,
popToTop: (params?: { immediate?: boolean }) => boolean,
isFocused: () => boolean,
reset?: (actions: NavigationAction[], index: number) => boolean,
dismiss?: () => boolean,
// DrawerRouter action creators
openDrawer?: () => boolean,
closeDrawer?: () => boolean,
toggleDrawer?: () => boolean,
};
declare export type NavigationNavigatorProps<O: {}, S: {}> = $Shape<{