Skip to content

Instantly share code, notes, and snippets.

@bvaughn
Created September 26, 2016 20:37
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bvaughn/3f356e79416e52b58a9150a179632a5a to your computer and use it in GitHub Desktop.
Save bvaughn/3f356e79416e52b58a9150a179632a5a to your computer and use it in GitHub Desktop.
Helper class for animating properties in React
import now from 'performance-now';
import raf from 'raf';
import { Component, PropTypes } from 'react';
export default class Transition extends Component {
static propTypes = {
active: PropTypes.bool.isRequired,
children: PropTypes.func.isRequired,
duration: PropTypes.number.isRequired,
fromValue: PropTypes.number.isRequired,
interpolator: PropTypes.func.isRequired,
repeat: PropTypes.bool.isRequired,
toValue: PropTypes.number.isRequired
};
static defaultProps = {
active: false,
duration: 1000,
fromValue: 0,
interpolator: (value) => value,
repeat: false,
toValue: 1
};
constructor (props, context) {
super(props, context);
this._timeTotal = 0;
this.state = {
currentValue: props.fromValue
};
}
componentDidMount () {
const { active } = this.props;
if (active) {
this.startAnimation();
}
}
componentDidUpdate (prevProps, prevState) {
const { active, duration, repeat } = this.props;
if (active) {
if (duration > this._timeTotal) {
this.startAnimation();
} else if (repeat) {
this._timeTotal = 0;
this.startAnimation();
}
}
}
componentWillUpdate (nextProps, nextState) {
const { active } = this.props;
if (active !== nextProps.active) {
if (nextProps.active) {
this.startAnimation();
} else {
this.cancelAnimation();
}
}
}
render () {
const { children } = this.props;
const { currentValue } = this.state;
return children(currentValue);
}
cancelAnimation () {
raf.cancel(this._afid);
}
startAnimation () {
this._timeNow = now();
this._afid = raf(() => {
const { duration, fromValue, interpolator, toValue } = this.props;
this._timeTotal += now() - this._timeNow;
const delta = Math.max(1, duration / this._timeTotal);
const interpolated = interpolator(delta);
const currentValue = (toValue - fromValue) / interpolated;
this.setState({ currentValue });
});
}
}
// Example usage:
<Transition
active
duration={5000}
fromValue={0}
toValue={1}
>
{(currentValue) => (
<div style={{ opacity: currentValue }}>
Component
</div>
)}
</Transition>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment