[ReactNative] Avoid navigator scene renders during transition
This commit is contained in:
parent
50959dd42c
commit
75d52b0f33
|
@ -71,7 +71,7 @@ var styles = StyleSheet.create({
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
top: 0,
|
top: 0,
|
||||||
},
|
},
|
||||||
presentNavItem: {
|
currentScene: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
left: 0,
|
left: 0,
|
||||||
|
@ -79,7 +79,7 @@ var styles = StyleSheet.create({
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
top: 0,
|
top: 0,
|
||||||
},
|
},
|
||||||
futureNavItem: {
|
futureScene: {
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
left: 0,
|
left: 0,
|
||||||
|
@ -991,9 +991,42 @@ var Navigator = React.createClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_routeToOptimizedStackItem: function(route, i) {
|
_renderOptimizedScenes: function() {
|
||||||
var shouldUpdateChild =
|
// To avoid rendering scenes that are not visible, we use
|
||||||
this.state.updatingRangeLength !== 0 &&
|
// updatingRangeStart and updatingRangeLength to track the scenes that need
|
||||||
|
// to be updated.
|
||||||
|
|
||||||
|
// To avoid visual glitches, we never re-render scenes during a transition.
|
||||||
|
// We assume that `state.updatingRangeLength` will have a length during the
|
||||||
|
// initial render of any scene
|
||||||
|
var shouldRenderScenes = !this.state.isAnimating &&
|
||||||
|
this.state.updatingRangeLength !== 0;
|
||||||
|
if (shouldRenderScenes) {
|
||||||
|
return (
|
||||||
|
<StaticContainer shouldUpdate={true}>
|
||||||
|
<View
|
||||||
|
style={styles.transitioner}
|
||||||
|
{...this.panGesture.panHandlers}
|
||||||
|
onResponderTerminationRequest={
|
||||||
|
this._handleResponderTerminationRequest
|
||||||
|
}>
|
||||||
|
{this.state.routeStack.map(this._renderOptimizedScene)}
|
||||||
|
</View>
|
||||||
|
</StaticContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// If no scenes are changing, we can save render time. React will notice
|
||||||
|
// that we are rendering a StaticContainer in the same place, so the
|
||||||
|
// existing element will be updated. When React asks the element
|
||||||
|
// shouldComponentUpdate, the StaticContainer will return false, and the
|
||||||
|
// children from the previous reconciliation will remain.
|
||||||
|
return (
|
||||||
|
<StaticContainer shouldUpdate={false} />
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
_renderOptimizedScene: function(route, i) {
|
||||||
|
var shouldRenderScene =
|
||||||
i >= this.state.updatingRangeStart &&
|
i >= this.state.updatingRangeStart &&
|
||||||
i <= this.state.updatingRangeStart + this.state.updatingRangeLength;
|
i <= this.state.updatingRangeStart + this.state.updatingRangeLength;
|
||||||
var sceneNavigatorContext = {
|
var sceneNavigatorContext = {
|
||||||
|
@ -1003,49 +1036,38 @@ var Navigator = React.createClass({
|
||||||
this.navigatorContext.setHandlerForRoute(route, handler);
|
this.navigatorContext.setHandlerForRoute(route, handler);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
var child = this.props.renderScene(
|
var scene = shouldRenderScene ?
|
||||||
route,
|
this._renderScene(route, i, sceneNavigatorContext) : null;
|
||||||
sceneNavigatorContext
|
|
||||||
);
|
|
||||||
var initialSceneStyle =
|
|
||||||
i === this.state.presentedIndex ? styles.presentNavItem : styles.futureNavItem;
|
|
||||||
return (
|
return (
|
||||||
<NavigatorStaticContextContainer
|
<NavigatorStaticContextContainer
|
||||||
navigatorContext={sceneNavigatorContext}
|
navigatorContext={sceneNavigatorContext}
|
||||||
key={'nav' + i}
|
key={'nav' + i}
|
||||||
shouldUpdate={shouldUpdateChild}>
|
shouldUpdate={shouldRenderScene}>
|
||||||
<View
|
{scene}
|
||||||
key={this.state.idStack[i]}
|
|
||||||
ref={'scene_' + i}
|
|
||||||
style={[initialSceneStyle, this.props.sceneStyle]}>
|
|
||||||
{React.cloneElement(child, {
|
|
||||||
ref: this._handleItemRef.bind(null, this.state.idStack[i]),
|
|
||||||
})}
|
|
||||||
</View>
|
|
||||||
</NavigatorStaticContextContainer>
|
</NavigatorStaticContextContainer>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
renderNavigationStackItems: function() {
|
_renderScene: function(route, i, sceneNavigatorContext) {
|
||||||
var shouldRecurseToNavigator = this.state.updatingRangeLength !== 0;
|
var child = this.props.renderScene(
|
||||||
// If not recursing update to navigator at all, may as well avoid
|
route,
|
||||||
// computation of navigator children.
|
sceneNavigatorContext
|
||||||
var items = shouldRecurseToNavigator ?
|
);
|
||||||
this.state.routeStack.map(this._routeToOptimizedStackItem) : null;
|
var initialSceneStyle = i === this.state.presentedIndex ?
|
||||||
|
styles.currentScene : styles.futureScene;
|
||||||
return (
|
return (
|
||||||
<StaticContainer shouldUpdate={shouldRecurseToNavigator}>
|
<View
|
||||||
<View
|
key={this.state.idStack[i]}
|
||||||
style={styles.transitioner}
|
ref={'scene_' + i}
|
||||||
{...this.panGesture.panHandlers}
|
style={[initialSceneStyle, this.props.sceneStyle]}>
|
||||||
onResponderTerminationRequest={this._handleResponderTerminationRequest}>
|
{React.cloneElement(child, {
|
||||||
{items}
|
ref: this._handleItemRef.bind(null, this.state.idStack[i]),
|
||||||
</View>
|
})}
|
||||||
</StaticContainer>
|
</View>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
renderNavigationStackBar: function() {
|
_renderNavigationBar: function() {
|
||||||
if (!this.props.navigationBar) {
|
if (!this.props.navigationBar) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1059,8 +1081,8 @@ var Navigator = React.createClass({
|
||||||
render: function() {
|
render: function() {
|
||||||
return (
|
return (
|
||||||
<View style={[styles.container, this.props.style]}>
|
<View style={[styles.container, this.props.style]}>
|
||||||
{this.renderNavigationStackItems()}
|
{this._renderOptimizedScenes()}
|
||||||
{this.renderNavigationStackBar()}
|
{this._renderNavigationBar()}
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue