Simple Redux Animation

by Dominic Cocchiarella

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-with-addons.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/3.5.2/redux.js"></script>
<div id="container"></div>

CSS

*, *::before, *::after {
  box-sizing: inherit;
}

html, body, 
#container, 
.container-inner {
  height: 100%;
  box-sizing: border-box;
  margin: 0;
}

.main-content {
  height: 100%;
  background-color: #43B02A;
}

.absolute-center {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  margin: auto;
}
  
.logo-wrapper {
  width: 298px;
  height: 60px;
}

.logo-white,
.logo-color {
  width: 100%;
  height: 100%;
  background-size: 100%;
  background-repeat: no-repeat;
  opacity: 1;
  will-change: opacity;
}

.logo-white {
  background-image: url(https://d2guulkeunn7d8.cloudfront.net/assets/beetstrap/brand/instacart-logo-white@2x-fb1feeeb27989918f03cae5707183b27.png);
}

.logo-color {
  background-image: url(https://d2guulkeunn7d8.cloudfront.net/assets/beetstrap/brand/instacart-logo-color@2x-0f6d941e7e53120ce96166e1d6f2adc4.png);
}

Babel + JSX

// importing isn't possible on jsFiddle, so we fake th Redux imports here
let combineReducers = Redux.combineReducers
let createStore = Redux.createStore

const BACKGROUND_POS_START = 50

// these will be used as styles in our React component later
const defaultLogoState = {
  animationProgress : 0,
  backgroundPos     : BACKGROUND_POS_START
}

// Redux reducer
const logoReducer = function(state = defaultLogoState, action) {
  switch (action.type){
    case 'LOGO.SET_NEXT_ANIMATION_STEP':
      let progress = action.progress

      // calculate the background position from 
      // progress and BACKGROUND_POS_START
      return Object.assign({}, state, {
        animationProgress : progress,
        backgroundPos     : Math.floor(BACKGROUND_POS_START - (progress * BACKGROUND_POS_START)),
      })
    default:
      return state
  }
}

// Redux action
// We'll dispatch this on every frame to animate the element
const logoAnimationStep = function(progress) {
    return {
      type: 'LOGO.SET_NEXT_ANIMATION_STEP',
    progress: progress
  }
}

// Redux store
const storeApp = createStore(logoReducer, defaultLogoState);

const Logo = React.createClass({  
  render: function() {
    // this is where we use the state/props generated by the Redux
    // store to style our element
    let wrapperStyles = {
      transform: `translateY(${this.props.backgroundPos}px)`
    }

    return (
      <div 
        className='logo-wrapper absolute-center'
        style={wrapperStyles}
      >
        <a
          className='logo-white absolute-center'
          href={'http://www.instacart.com'}
          target={'_blank'}
        >
        </a>
      </div>
    )
  }
})

// Main container component
const Container = React.createClass({
  getInitialState: function() {
    // set the intial state of your container component
    // to the state of the Redux store
    return storeApp.getState()
  },
  
  componentDidMount: function() {
    // subscribe to the Redux store's state...