Reduce extra rendering in NavigationCard

Summary: This adds a new SceneView with a shouldComponentUpdate policy of only re-rendering when the scene's state changes. This allows avoidance of extra re-renders. Results in a much smoother back-swipe gesture because we no longer re-render scenes as we transition from gesture to animation.

Reviewed By: hedgerwang

Differential Revision: D3219545

fb-gh-sync-id: 7c04e0e4ebb40d1e57ef7af11e2e54adf4f52aa0
fbshipit-source-id: 7c04e0e4ebb40d1e57ef7af11e2e54adf4f52aa0
This commit is contained in:
Eric Vicenti 2016-05-03 13:30:24 -07:00 committed by Facebook Github Bot 2
parent 20d53b1f23
commit bb39a2e9da
2 changed files with 46 additions and 17 deletions

View File

@ -1,4 +1,11 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* The examples provided by Facebook are for non-commercial testing and
* evaluation purposes only.
*
@ -15,26 +22,21 @@
*/
'use strict';
const ListView = require('ListView');
const React = require('react');
const ReactNative = require('react-native');
const StyleSheet = require('StyleSheet');
const Text = require('Text');
const TextInput = require('TextInput');
const NavigationContainer = require('NavigationContainer');
const TouchableHighlight = require('TouchableHighlight');
const View = require('View');
const UIExplorerActions = require('./UIExplorerActions');
const {
ListView,
NavigationExperimental,
StyleSheet,
Text,
TextInput,
TouchableHighlight,
View,
} = ReactNative;
const createExamplePage = require('./createExamplePage');
const {
Container: NavigationContainer,
} = NavigationExperimental;
import type {
UIExplorerExample,
} from './UIExplorerList.ios'
} from './UIExplorerList.ios';
const ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2,
@ -154,7 +156,7 @@ class UIExplorerExampleList extends React.Component {
}
_handleRowPress(exampleKey: string): void {
this.props.onNavigate(UIExplorerActions.ExampleAction(exampleKey))
this.props.onNavigate(UIExplorerActions.ExampleAction(exampleKey));
}
}
@ -167,7 +169,7 @@ function makeRenderable(example: any): ReactClass<any> {
UIExplorerExampleList = NavigationContainer.create(UIExplorerExampleList);
UIExplorerExampleList.makeRenderable = makeRenderable;
var styles = StyleSheet.create({
const styles = StyleSheet.create({
listContainer: {
flex: 1,
},

View File

@ -51,6 +51,11 @@ import type {
NavigationSceneRendererProps,
} from 'NavigationTypeDefinition';
type SceneViewProps = {
sceneRenderer: NavigationSceneRenderer,
sceneRendererProps: NavigationSceneRendererProps,
};
type Props = NavigationSceneRendererProps & {
onComponentRef: (ref: any) => void,
panHandlers: ?NavigationPanPanHandlers,
@ -61,6 +66,25 @@ type Props = NavigationSceneRendererProps & {
const {PropTypes} = React;
class SceneView extends React.Component<any, SceneViewProps, any> {
static propTypes = {
sceneRenderer: PropTypes.func.isRequired,
sceneRendererProps: NavigationPropTypes.SceneRenderer,
};
shouldComponentUpdate(nextProps: SceneViewProps, nextState: any): boolean {
return (
nextProps.sceneRendererProps.scene.navigationState !==
this.props.sceneRendererProps.scene.navigationState
);
}
render(): ?ReactElement {
return this.props.sceneRenderer(this.props.sceneRendererProps);
}
}
/**
* Component that renders the scene as card for the <NavigationCardStack />.
*/
@ -107,7 +131,10 @@ class NavigationCard extends React.Component<any, Props, any> {
pointerEvents={pointerEvents}
ref={this.props.onComponentRef}
style={[styles.main, viewStyle]}>
{renderScene(props)}
<SceneView
sceneRenderer={renderScene}
sceneRendererProps={props}
/>
</Animated.View>
);
}