Clean up NavigationAnimatedView

Summary:- Add flow type checks.
- Fix code styles.
- Improve the logics to update `this.state.scenes`.
- Improve the logics to pass the layout.

Reviewed By: ericvicenti

Differential Revision: D3022107

fb-gh-sync-id: 23f4ed22db797f68bde0ba4f3cdd123701934fc3
shipit-source-id: 23f4ed22db797f68bde0ba4f3cdd123701934fc3
This commit is contained in:
Hedger Wang 2016-03-08 10:56:58 -08:00 committed by Facebook Github Bot 6
parent e76fb68141
commit b5ae8a8ece

View File

@ -21,9 +21,11 @@ const View = require('View');
import type { import type {
NavigationAnimatedValue, NavigationAnimatedValue,
NavigationAnimationSetter, NavigationAnimationSetter,
NavigationLayout,
NavigationParentState, NavigationParentState,
NavigationScene, NavigationScene,
NavigationSceneRenderer, NavigationSceneRenderer,
NavigationState,
} from 'NavigationTypeDefinition'; } from 'NavigationTypeDefinition';
/** /**
@ -102,71 +104,87 @@ const defaultProps = {
class NavigationAnimatedView class NavigationAnimatedView
extends React.Component<any, Props, State> { extends React.Component<any, Props, State> {
_animatedHeight: Animated.Value; _layout: NavigationLayout;
_animatedWidth: Animated.Value; _onLayout: (event: any) => void;
_lastHeight: number; _onProgressChange: (data: {value: number}) => void;
_lastWidth: number;
_positionListener: any; _positionListener: any;
props: Props; props: Props;
state: State; state: State;
constructor(props) { constructor(props: Props, context: any) {
super(props); super(props, context);
this._lastWidth = 0;
this._lastHeight = 0; this._layout = {
this._animatedHeight = new Animated.Value(this._lastHeight); initWidth: 0,
this._animatedWidth = new Animated.Value(this._lastWidth); initHeight: 0,
width: new Animated.Value(0),
height: new Animated.Value(0),
};
this.state = { this.state = {
position: new Animated.Value(this.props.navigationState.index), position: new Animated.Value(this.props.navigationState.index),
scenes: [], scenes: this._reduceScenes([], this.props.navigationState),
}; };
} }
componentWillMount() {
this.setState({ componentWillMount(): void {
scenes: this._reduceScenes(this.state.scenes, this.props.navigationState), this._onLayout = this._onLayout.bind(this);
}); this._onProgressChange = this._onProgressChange.bind(this);
} }
componentDidMount() {
this._positionListener = this.state.position.addListener(this._onProgressChange.bind(this)); componentDidMount(): void {
this._positionListener =
this.state.position.addListener(this._onProgressChange);
} }
componentWillReceiveProps(nextProps) {
componentWillReceiveProps(nextProps: Props): void {
if (nextProps.navigationState !== this.props.navigationState) { if (nextProps.navigationState !== this.props.navigationState) {
this.setState({ this.setState({
scenes: this._reduceScenes(this.state.scenes, nextProps.navigationState, this.props.navigationState), scenes: this._reduceScenes(
this.state.scenes,
nextProps.navigationState,
this.props.navigationState
),
}); });
} }
} }
componentDidUpdate(lastProps) {
if (lastProps.navigationState.index !== this.props.navigationState.index && this.props.setTiming) { componentDidUpdate(lastProps: Props): void {
this.props.setTiming(this.state.position, this.props.navigationState, lastProps.navigationState); if (lastProps.navigationState.index !== this.props.navigationState.index) {
this.props.setTiming(
this.state.position,
this.props.navigationState,
lastProps.navigationState
);
} }
} }
componentWillUnmount() {
if (this._positionListener) { componentWillUnmount(): void {
this.state.position.removeListener(this._positionListener); this.state.position.removeListener(this._positionListener);
this._positionListener = null;
}
} }
_onProgressChange(data: Object): void { _onProgressChange(data: Object): void {
if (Math.abs(data.value - this.props.navigationState.index) > Number.EPSILON) { const delta = Math.abs(data.value - this.props.navigationState.index);
if (delta > Number.EPSILON) {
return; return;
} }
this.state.scenes.forEach((scene, index) => {
if (scene.isStale) { const scenes = this.state.scenes.filter(scene => {
const scenes = this.state.scenes.slice(); return !scene.isStale;
scenes.splice(index, 1);
this.setState({ scenes, });
}
}); });
if (scenes.length !== this.state.scenes.length) {
this.setState({ scenes });
}
} }
_reduceScenes( _reduceScenes(
scenes: Array<NavigationScene>, scenes: Array<NavigationScene>,
nextState: NavigationParentState, nextState: NavigationParentState,
lastState: ?NavigationParentState lastState: ?NavigationParentState
): Array<NavigationScene> { ): Array<NavigationScene> {
let nextScenes = nextState.children.map((child, index) => { const nextScenes = nextState.children.map((child, index) => {
return { return {
index, index,
isStale: false, isStale: false,
@ -175,8 +193,11 @@ class NavigationAnimatedView
}); });
if (lastState) { if (lastState) {
lastState.children.forEach((child, index) => { lastState.children.forEach((child: NavigationState, index: number) => {
if (!NavigationStateUtils.get(nextState, child.key) && index !== nextState.index) { if (
!NavigationStateUtils.get(nextState, child.key) &&
index !== nextState.index
) {
nextScenes.push({ nextScenes.push({
index, index,
isStale: true, isStale: true,
@ -186,38 +207,21 @@ class NavigationAnimatedView
}); });
} }
nextScenes = nextScenes.sort(compareScenes); return nextScenes.sort(compareScenes);
return nextScenes;
} }
render() {
render(): ReactElement {
return ( return (
<View <View
onLayout={(e) => { onLayout={this._onLayout}
const {height, width} = e.nativeEvent.layout;
this._animatedHeight &&
this._animatedHeight.setValue(height);
this._animatedWidth &&
this._animatedWidth.setValue(width);
this._lastHeight = height;
this._lastWidth = width;
}}
style={this.props.style}> style={this.props.style}>
{this.state.scenes.map(this._renderScene, this)} {this.state.scenes.map(this._renderScene, this)}
{this._renderOverlay()} {this._renderOverlay()}
</View> </View>
); );
} }
_getLayout() {
return {
height: this._animatedHeight,
width: this._animatedWidth,
initWidth: this._lastWidth,
initHeight: this._lastHeight,
};
}
_renderScene(scene: NavigationScene) { _renderScene(scene: NavigationScene): ?ReactElement {
const { const {
navigationState, navigationState,
onNavigate, onNavigate,
@ -230,7 +234,7 @@ class NavigationAnimatedView
} = this.state; } = this.state;
return renderScene({ return renderScene({
layout: this._getLayout(), layout: this._layout,
navigationState, navigationState,
onNavigate, onNavigate,
position, position,
@ -239,7 +243,7 @@ class NavigationAnimatedView
}); });
} }
_renderOverlay() { _renderOverlay(): ?ReactElement {
if (this.props.renderOverlay) { if (this.props.renderOverlay) {
const { const {
navigationState, navigationState,
@ -253,7 +257,7 @@ class NavigationAnimatedView
} = this.state; } = this.state;
return renderOverlay({ return renderOverlay({
layout: this._getLayout(), layout: this._layout,
navigationState, navigationState,
onNavigate, onNavigate,
position, position,
@ -263,6 +267,21 @@ class NavigationAnimatedView
} }
return null; return null;
} }
_onLayout(event: any): void {
const {height, width} = event.nativeEvent.layout;
const layout = {
...this._layout,
initHeight: height,
initWidth: width,
};
this._layout = layout;
layout.height.setValue(height);
layout.width.setValue(width);
}
} }
NavigationAnimatedView.propTypes = propTypes; NavigationAnimatedView.propTypes = propTypes;