How to build animated microinteractions in React
create-react-app
GitHub - facebookincubator/create-react-app: Create React apps with no build configuration.
create-react-app search-box-animation
cd search-box-animation
npm install --save material-ui react-tap-event-plugin
Using Higher Order Components to Separate Concerns
Higher Order Components (HOC) are functions that return a new component.
Animation
CSS transition and CSS animation Expanding: GitHub - csepulv/search-box-animation at expanding
react-motion
react-animations and aphrodite(or radium)
Putting It Together: Composing a Complex Component
import React, {Component} from 'react';
import {headShake} from 'react-animations';
import {StyleSheet, css} from 'aphrodite';
const styles = StyleSheet.create({
    headShake: {
        animationName: headShake,
        animationDuration: '1s'
    }
});
const makeShakeAnimation = (Target) => {
    return class extends Component {
        constructor(props) {
            super(props);
            this.state = {startShake: props.shouldShake};
        }
        componentWillReceiveProps(nextProps) {
            this.setState({startShake: nextProps.shouldShake}, () => {
                const self = this;
                setTimeout(() => self.setState({startShake: false}), 1000);
            });
            //https://css-tricks.com/restart-css-animation/ for discussion on restart
        }
        render() {
            return (
                <Target {...this.props}
                        frameClass={this.state.startShake ? css(styles.headShake) : ''}/>
            );
        }
    }
};
export default makeShakeAnimation;
import React, {Component} from 'react';
import makeExpanding from './expanding-animation';
import makeShakingAnimation from './shake-animation';
const makeAnimatedValidationSearchBox = (Target) => {
    const WrappedComponent = makeShakingAnimation(makeExpanding(Target));
    return class extends Component {
        constructor(props) {
            super(props);
            this.state = {query: '', hasError: false};
        }
        onQueryUpdate = (value) => {
            this.setState({query: value, hasError:false});
        };
        onSubmit = () => {
            this.setState({hasError: true});
        };
        render() {
            return (
                <WrappedComponent
                    onQueryUpdate={this.onQueryUpdate}
                    query={this.state.query}
                    onSubmit={this.onSubmit}
                    shouldShake={this.state.hasError}
                />
            );
        }
    }
};
export default makeAnimatedValidationSearchBox;