Merge pull request #49 from react-navigation/@brent/queued-transitions

Rethink queued transitions
This commit is contained in:
Brent Vatne 2018-10-30 10:35:03 -07:00 committed by GitHub
commit 61a8f2253b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 88 additions and 43 deletions

View File

@ -9,11 +9,29 @@ const Buttons = withNavigation(props => (
title="Go to Details"
onPress={() => props.navigation.navigate('Details')}
/>
<Button
title="Go and then go to details quick"
onPress={() => {
props.navigation.pop();
setTimeout(() => {
props.navigation.navigate('Details');
}, 100);
}}
/>
<Button
title="Go to Headerless"
onPress={() => props.navigation.navigate('Headerless')}
/>
<Button title="Go back" onPress={() => props.navigation.goBack()} />
<Button
title="Go back quick"
onPress={() => {
props.navigation.pop();
setTimeout(() => {
props.navigation.pop();
}, 100);
}}
/>
<Button
title="Go back to all examples"
onPress={() => props.navigation.navigate('Home')}
@ -26,6 +44,14 @@ class ListScreen extends React.Component {
title: 'List',
};
componentDidMount() {
console.log('ListScreen didMount');
}
componentWillUnmount() {
console.log('ListScreen willUnmount');
}
render() {
return (
<View
@ -52,6 +78,14 @@ class DetailsScreen extends React.Component {
},
};
componentDidMount() {
console.log('DetailsScreen didMount');
}
componentWillUnmount() {
console.log('DetailsScreen willUnmount');
}
render() {
return (
<View
@ -81,6 +115,14 @@ class HeaderlessScreen extends React.Component {
header: null,
};
componentDidMount() {
console.log('HeaderlessScreen didMount');
}
componentWillUnmount() {
console.log('HeaderlessScreen willUnmount');
}
render() {
return (
<View

View File

@ -51,6 +51,7 @@ class Transitioner extends React.Component {
this._prevTransitionProps = null;
this._transitionProps = buildTransitionProps(props, this.state);
this._isMounted = false;
this._isTransitionRunning = false;
this._queuedTransition = null;
@ -68,22 +69,29 @@ class Transitioner extends React.Component {
// eslint-disable-next-line react/no-deprecated
componentWillReceiveProps(nextProps) {
if (this._isTransitionRunning && !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);
}
}
_computeScenes = (props, nextProps) => {
let nextScenes = NavigationScenesReducer(
this.state.scenes,
nextProps.navigation.state,
this.props.navigation.state,
props.navigation.state,
nextProps.descriptors
);
// We are adding one or more scene! We can't handle a case where the number
// of scenes increases and one or more of the new scenes is not in the
// current navigation state, so we filter anything that's not in the
// navigation state right now out and assume it has been transitioned out
// properly beforehand.
if (nextScenes.length > this.state.scenes.length) {
nextScenes = filterNotInState(nextScenes, nextProps.navigation.state);
}
if (!nextProps.navigation.state.isTransitioning) {
nextScenes = filterStale(nextScenes);
}
@ -102,15 +110,8 @@ class Transitioner extends React.Component {
console.log({ nextScenes: nextScenes.map(s => s.descriptor.key) });
}
const indexHasChanged =
nextProps.navigation.state.index !== this.props.navigation.state.index;
if (this._isTransitionRunning) {
this._queuedTransition = { nextProps, nextScenes, indexHasChanged };
return;
}
this._startTransition(nextProps, nextScenes, indexHasChanged);
}
return nextScenes;
};
_startTransition(nextProps, nextScenes, indexHasChanged) {
const nextState = {
@ -118,6 +119,13 @@ class Transitioner extends React.Component {
scenes: nextScenes,
};
if (__DEV__ && DEBUG) {
console.log({
startTransition: true,
nextScenes: nextScenes.map(s => s.descriptor.key),
});
}
// grab the position animated value
const { position } = nextState;
@ -127,6 +135,7 @@ 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
@ -199,7 +208,9 @@ class Transitioner extends React.Component {
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,
});
@ -253,6 +264,10 @@ 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 () => {
@ -268,11 +283,19 @@ class Transitioner extends React.Component {
}
if (this._queuedTransition) {
this._startTransition(
this._queuedTransition.nextProps,
this._queuedTransition.nextScenes,
this._queuedTransition.indexHasChanged
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;
}
this._queuedTransition = null;
} else {
this._isTransitionRunning = false;
@ -313,26 +336,6 @@ function filterStale(scenes) {
return filtered;
}
function filterNotInState(scenes, state) {
let activeKeys = state.routes.map(r => r.key);
let filtered = scenes.filter(scene =>
activeKeys.includes(scene.descriptor.key)
);
if (__DEV__ && DEBUG) {
console.log({
activeKeys,
filtered: filtered.map(s => s.descriptor.key),
scenes: scenes.map(s => s.descriptor.key),
});
}
if (filtered.length === scenes.length) {
return scenes;
}
return filtered;
}
function isSceneActive(scene) {
return scene.isActive;
}