[RN] Refactor SideBar layout and animation (coding style)

This commit is contained in:
Lyubo Marinov 2018-06-01 14:53:46 -05:00
parent c700261852
commit c6d553738f
2 changed files with 41 additions and 47 deletions

View File

@ -1,11 +1,7 @@
// @flow // @flow
import React, { Component, type Node } from 'react'; import React, { Component, type Node } from 'react';
import { import { Animated, TouchableWithoutFeedback, View } from 'react-native';
Animated,
TouchableWithoutFeedback,
View
} from 'react-native';
import styles, { SIDEBAR_WIDTH } from './styles'; import styles, { SIDEBAR_WIDTH } from './styles';
@ -15,21 +11,21 @@ import styles, { SIDEBAR_WIDTH } from './styles';
type Props = { type Props = {
/** /**
* The children of the Component * The children of {@code SideBar}.
*/ */
children: Node, children: Node,
/** /**
* Callback to notify the containing Component that the sidebar is * Callback to notify the containing {@code Component} that the sidebar is
* closing. * closing.
*/ */
onHide: Function, onHide: Function,
/** /**
* Sets the menu displayed or hidden. * Whether the menu (of the {@code SideBar}?) is displayed/rendered/shown.
*/ */
show: boolean show: boolean
} };
/** /**
* The type of the React {@code Component} state of {@link SideBar}. * The type of the React {@code Component} state of {@link SideBar}.
@ -37,18 +33,18 @@ type Props = {
type State = { type State = {
/** /**
* Indicates whether the side overlay should be rendered or not. * Whether the side overlay should be displayed/rendered/shown.
*/ */
showOverlay: boolean, showOverlay: boolean,
/** /**
* The native animation object. * The native animation object.
*/ */
sliderAnimation: Object sliderAnimation: Animated.Value
} };
/** /**
* A generic animated side bar to be used for left side menus * A generic animated side bar to be used for left-side, hamburger-style menus.
*/ */
export default class SideBar extends Component<Props, State> { export default class SideBar extends Component<Props, State> {
/** /**
@ -64,11 +60,12 @@ export default class SideBar extends Component<Props, State> {
sliderAnimation: new Animated.Value(0) sliderAnimation: new Animated.Value(0)
}; };
// Bind event handlers so they are only bound once per instance.
this._onHideMenu = this._onHideMenu.bind(this); this._onHideMenu = this._onHideMenu.bind(this);
} }
/** /**
* Implements the Component's componentDidMount method. * Implements React's {@link Component#componentDidMount()}.
* *
* @inheritdoc * @inheritdoc
*/ */
@ -77,14 +74,12 @@ export default class SideBar extends Component<Props, State> {
} }
/** /**
* Implements the Component's componentWillReceiveProps method. * Implements React's {@link Component#componentWillReceiveProps()}.
* *
* @inheritdoc * @inheritdoc
*/ */
componentWillReceiveProps(newProps: Props) { componentWillReceiveProps({ show }: Props) {
if (newProps.show !== this.props.show) { (show === this.props.show) || this._setShow(show);
this._setShow(newProps.show);
}
} }
/** /**
@ -120,17 +115,16 @@ export default class SideBar extends Component<Props, State> {
* @returns {Array<Object>} * @returns {Array<Object>}
*/ */
_getContentStyle() { _getContentStyle() {
const { sliderAnimation } = this.state; return [
const transformStyle styles.sideMenuContent,
= { transform: [ { translateX: sliderAnimation } ] }; { transform: [ { translateX: this.state.sliderAnimation } ] }
];
return [ styles.sideMenuContent, transformStyle ];
} }
_onHideMenu: () => void; _onHideMenu: () => void;
/** /**
* Hides the menu. * Hides the side menu.
* *
* @private * @private
* @returns {void} * @returns {void}
@ -146,28 +140,30 @@ export default class SideBar extends Component<Props, State> {
_setShow: (boolean) => void; _setShow: (boolean) => void;
/** /**
* Sets the side menu visible or hidden. * Shows/hides the side menu.
* *
* @param {boolean} show - The new expected visibility value. * @param {boolean} show - If the side menu is to be made visible,
* {@code true}; otherwise, {@code false}.
* @private * @private
* @returns {void} * @returns {void}
*/ */
_setShow(show) { _setShow(show) {
if (show) { show && this.setState({ showOverlay: true });
this.setState({ showOverlay: true });
}
Animated Animated
.timing( .timing(
this.state.sliderAnimation, /* value */ this.state.sliderAnimation,
{ /* config */ {
toValue: show ? SIDEBAR_WIDTH : 0, toValue: show ? SIDEBAR_WIDTH : 0,
useNativeDriver: true useNativeDriver: true
}) })
.start(animationState => { .start(({ finished }) => {
if (animationState.finished && !show) { finished && !show && this.setState({ showOverlay: false });
this.setState({ showOverlay: false });
} // XXX Technically, the arrow function can further be simplified
// by removing the {} and returning the boolean expression
// above. Practically and unfortunately though, Flow freaks out
// and states that Animated.timing doesn't exist!?
}); });
} }
} }

View File

@ -1,10 +1,8 @@
// @flow
import { StyleSheet } from 'react-native'; import { StyleSheet } from 'react-native';
import { import { BoxModel, ColorPalette, createStyleSheet } from '../../../styles';
BoxModel,
ColorPalette,
createStyleSheet
} from '../../../styles';
const AVATAR_OPACITY = 0.4; const AVATAR_OPACITY = 0.4;
const AVATAR_SIZE = 65; const AVATAR_SIZE = 65;
@ -21,7 +19,7 @@ export const UNDERLAY_COLOR = 'rgba(255, 255, 255, 0.2)';
const HEADER_STYLES = { const HEADER_STYLES = {
/** /**
* Platform specific header button (e.g. back, menu...etc). * Platform specific header button (e.g. back, menu, etc).
*/ */
headerButton: { headerButton: {
alignSelf: 'center', alignSelf: 'center',
@ -57,7 +55,7 @@ const HEADER_STYLES = {
}, },
/** /**
* Base style of Header * Base style of Header.
*/ */
screenHeader: { screenHeader: {
alignItems: 'center', alignItems: 'center',
@ -293,8 +291,8 @@ const SIDEBAR_STYLES = {
}, },
/** /**
* The opaque area that covers the rest of the screen, when * The opaque area that covers the rest of the screen, when the side bar is
* the side bar is open. * open.
*/ */
sideMenuShadow: { sideMenuShadow: {
...StyleSheet.absoluteFillObject, ...StyleSheet.absoluteFillObject,
@ -303,8 +301,8 @@ const SIDEBAR_STYLES = {
}; };
/** /**
* The styles of the React {@code Components} of the generic components * The styles of the generic React {@code Component}s implemented by the feature
* in the app. * base/react.
*/ */
export default createStyleSheet({ export default createStyleSheet({
...HEADER_STYLES, ...HEADER_STYLES,