Clean up transitioner a bit, fix issue where state is invalid and warn

This commit is contained in:
Brent Vatne 2018-10-30 13:08:06 -07:00
parent a9f6d467d2
commit c27ed1b4b8
6 changed files with 116 additions and 56 deletions

View File

@ -15,6 +15,7 @@ import ModalStack from './src/ModalStack';
import LifecycleInteraction from './src/LifecycleInteraction';
import GestureInteraction from './src/GestureInteraction';
import SwitchWithStacks from './src/SwitchWithStacks';
import StackWithDrawer from './src/StackWithDrawer';
// Comment the following two lines to stop using react-native-screens
import { useScreens } from 'react-native-screens';
@ -48,6 +49,11 @@ const data = [
title: 'Switch with Stacks',
routeName: 'SwitchWithStacks',
},
{
component: StackWithDrawer,
title: 'Stack with drawer inside',
routeName: 'StackWithDrawer',
},
];
// Cache images

View File

@ -17,7 +17,9 @@
"react": "16.3.1",
"react-native": "~0.55.4",
"react-native-paper": "2.0.0-alpha.4",
"react-native-screens": "^1.0.0-alpha.9"
"react-native-screens": "^1.0.0-alpha.9",
"react-navigation-drawer": "^1.0.0-alpha",
"react-navigation-tabs": "^1.0.0-alpha"
},
"devDependencies": {
"babel-plugin-module-resolver": "^3.0.0",

View File

@ -0,0 +1,48 @@
import React from 'react';
import { Button, Text, View } from 'react-native';
import { createStackNavigator } from 'react-navigation-stack';
import { createDrawerNavigator } from 'react-navigation-drawer';
import { createBottomTabNavigator } from 'react-navigation-tabs';
function Menu({ navigation }) {
return (
<View style={{ flex: 1 }}>
<Button title="Open on top" onPress={() => navigation.navigate('Top')} />
</View>
);
}
class Fake extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text style={{ fontSize: 20 }}>
{this.props.navigation.getParam('title')}
</Text>
</View>
);
}
}
const Tab = createBottomTabNavigator({
Home: { screen: Fake, params: { title: 'Home' } },
Other: { screen: Fake, params: { title: 'Other' } },
});
const Drawer = createDrawerNavigator(
{
TabScreen: {
screen: Tab,
},
},
{
contentComponent: props => <Menu {...props} />,
}
);
const App = createStackNavigator({
Drawer: { screen: Drawer },
Top: { screen: Fake, params: { title: 'Top' } },
});
export default App;

View File

@ -4353,6 +4353,13 @@ react-native-svg@6.2.2:
lodash "^4.16.6"
pegjs "^0.10.0"
react-native-tab-view@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/react-native-tab-view/-/react-native-tab-view-1.2.0.tgz#0cc26a1c8e49b6c0d58a30363dbbe43954907c31"
integrity sha512-lpiWi3dog86Fu/W60DU12RKrFv3XuTv0lHMC56t2jlDqxLfVzG9ufV7li6Afl2S2ZicNU1Bob8WPgxVZc8egAA==
dependencies:
prop-types "^15.6.1"
react-native-vector-icons@4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/react-native-vector-icons/-/react-native-vector-icons-4.5.0.tgz#6b95619e64f62f05f579f74a01fe5640df95158b"
@ -4427,6 +4434,21 @@ react-native@~0.55.4:
xmldoc "^0.4.0"
yargs "^9.0.0"
react-navigation-drawer@^1.0.0-alpha:
version "1.0.0-alpha.5"
resolved "https://registry.yarnpkg.com/react-navigation-drawer/-/react-navigation-drawer-1.0.0-alpha.5.tgz#1ef75b5e9c7ae9c3011427a493bcc2714ea2c072"
integrity sha512-AD1AyqGpUb4coUw3KpJ7i/2RfTiE5RJfTDHVeBkpqc2wsXJ4PaWYGoxfvfWP910hJy8txYTnWWUinWmiD7aBgA==
react-navigation-tabs@^1.0.0-alpha:
version "1.0.0-alpha.4"
resolved "https://registry.yarnpkg.com/react-navigation-tabs/-/react-navigation-tabs-1.0.0-alpha.4.tgz#321c8cc19d14268d343a830689c741bb94c6ba80"
integrity sha512-ng8sCJmcQj1ciWaj0eJudQvYng/oL24konNPNudSrMyVKAfKr4+HcRPLY/rol+efLJ8UGjXGv2qdRNkBNeaLew==
dependencies:
hoist-non-react-statics "^2.5.0"
prop-types "^15.6.1"
react-lifecycles-compat "^3.0.4"
react-native-tab-view "^1.0.0"
react-proxy@^1.1.7:
version "1.1.8"
resolved "https://registry.yarnpkg.com/react-proxy/-/react-proxy-1.1.8.tgz#9dbfd9d927528c3aa9f444e4558c37830ab8c26a"

View File

@ -94,7 +94,15 @@ export default function ScenesReducer(
});
const nextKeys = new Set();
nextState.routes.forEach((route, index) => {
let nextRoutes = nextState.routes;
if (nextRoutes.length > nextState.index + 1) {
console.warn(
'StackRouter provided invalid state, index should always be the top route'
);
nextRoutes = nextState.routes.slice(0, nextState.index + 1);
}
nextRoutes.forEach((route, index) => {
const key = SCENE_KEY_PREFIX + route.key;
let descriptor = descriptors && descriptors[route.key];
@ -123,8 +131,15 @@ export default function ScenesReducer(
});
if (prevState) {
let prevRoutes = prevState.routes;
if (prevRoutes.length > prevState.index + 1) {
console.warn(
'Stack provided invalid state, index should always be the top route'
);
prevRoutes = prevRoutes.slice(0, prevState.index + 1);
}
// Look at the previous routes and classify any removed scenes as `stale`.
prevState.routes.forEach((route, index) => {
prevRoutes.forEach((route, index) => {
const key = SCENE_KEY_PREFIX + route.key;
if (freshScenes.has(key)) {
return;

View File

@ -11,8 +11,6 @@ const DefaultTransitionSpec = {
timing: Animated.timing,
};
const DEBUG = false;
class Transitioner extends React.Component {
constructor(props, context) {
super(props, context);
@ -69,19 +67,14 @@ class Transitioner extends React.Component {
// eslint-disable-next-line react/no-deprecated
componentWillReceiveProps(nextProps) {
if (this._isTransitionRunning && !this._queuedTransition) {
this._queuedTransition = { prevProps: this.props };
if (this._isTransitionRunning) {
if (!this._queuedTransition) {
this._queuedTransition = { prevProps: this.props };
}
return;
}
let nextScenes = this._computeScenes(this.props, nextProps);
const indexHasChanged =
nextProps.navigation.state.index !== this.props.navigation.state.index;
if (nextScenes) {
this._startTransition(nextProps, nextScenes, indexHasChanged);
}
this._startTransition(this.props, nextProps);
}
_computeScenes = (props, nextProps) => {
@ -106,26 +99,27 @@ class Transitioner extends React.Component {
return;
}
if (__DEV__ && DEBUG) {
console.log({ nextScenes: nextScenes.map(s => s.descriptor.key) });
}
return nextScenes;
};
_startTransition(nextProps, nextScenes, indexHasChanged) {
_startTransition(props, nextProps) {
const indexHasChanged =
props.navigation.state.index !== nextProps.navigation.state.index;
let nextScenes = this._computeScenes(props, nextProps);
if (!nextScenes) {
// prevTransitionProps are the same as transitionProps in this case
// because nothing changed
this._prevTransitionProps = this._transitionProps;
this._onTransitionEnd();
return;
}
const nextState = {
...this.state,
scenes: nextScenes,
};
if (__DEV__ && DEBUG) {
console.log({
startTransition: true,
nextScenes: nextScenes.map(s => s.descriptor.key),
});
}
// grab the position animated value
const { position } = nextState;
@ -135,7 +129,6 @@ class Transitioner extends React.Component {
// compute transitionProps
this._prevTransitionProps = this._transitionProps;
this._transitionProps = buildTransitionProps(nextProps, nextState);
let { isTransitioning } = this._transitionProps.navigation.state;
// if the state isn't transitioning that is meant to signal that we should
@ -205,17 +198,6 @@ class Transitioner extends React.Component {
}
render() {
if (__DEV__ && DEBUG) {
let key = this.props.navigation.state.key;
let routeName = this.props.navigation.state.routeName;
console.log({
render: true,
[key]: this.state.scenes.map(d => d.key),
route: routeName,
});
}
return (
<View onLayout={this._onLayout} style={styles.main}>
{this.props.render(this._transitionProps, this._prevTransitionProps)}
@ -264,10 +246,6 @@ class Transitioner extends React.Component {
scenes,
};
if (__DEV__ && DEBUG) {
console.log({ onTransitionEnd: true, scenes: scenes.map(s => s.key) });
}
this._transitionProps = buildTransitionProps(this.props, nextState);
this.setState(nextState, async () => {
@ -283,20 +261,9 @@ class Transitioner extends React.Component {
}
if (this._queuedTransition) {
const indexHasChanged =
this.props.navigation.state.index !==
this._queuedTransition.prevProps.navigation.state.index;
let nextScenes = this._computeScenes(
this._queuedTransition.prevProps,
this.props
);
if (nextScenes) {
this._startTransition(this.props, nextScenes, indexHasChanged);
} else {
this._isTransitionRunning = false;
}
let { prevProps } = this._queuedTransition;
this._queuedTransition = null;
this._startTransition(prevProps, this.props);
} else {
this._isTransitionRunning = false;
}