Created
December 27, 2017 16:09
-
-
Save pangolingo/15c26a8d6d015cb858c1924f72a4e719 to your computer and use it in GitHub Desktop.
A React Native higher-order component that converts an animated value to a number
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// @flow | |
import * as React from 'react'; | |
import { Animated } from 'react-native'; | |
type HOCProps = { | |
/** | |
* The distance that a ScrollView has been scrolled | |
*/ | |
[key: string]: Animated.Value | |
} | |
type State = { | |
/** | |
* The ScrollView scroll distance as an number instead of an Animated.Value | |
*/ | |
[key: string]: number, | |
} | |
/** | |
* This higher order component takes a component with an Animated.Value prop. | |
* Let's call it 'scrollDistance'. It returns a new component that converts | |
* the 'scrollDistance' animated value to an number using a listener. | |
* This new component then renders the original component, | |
* passing in the number 'scrollDistanceNumber'. | |
* @param {React.ComponentType<Props>} WrappedComponent - the original component that will | |
* receive the animated value as an number | |
* @param {string} propName - the name of the Animated Value property that should be converted into | |
* a usable number. | |
* @returns {React.ComponentType<Props>} - a new component with the original one inside | |
*/ | |
export default function AnimatedPropAsNumberHOC<Props: HOCProps>( | |
WrappedComponent: React.ComponentType<Props>, | |
propName: string, | |
): React.ComponentType<Props> { | |
// return the original component wrapped in a new component | |
return class extends React.Component<Props, State> { | |
/** | |
* @param {object} props - React component props | |
*/ | |
constructor(props: Props) { | |
super(props); | |
this.propNameNumber = `${propName}Number`; | |
this.state = { | |
[this.propNameNumber]: 0, | |
}; | |
} | |
/** | |
* When the component mounts, add a listener to the animated prop | |
*/ | |
componentWillMount() { | |
if (this.props[propName]) { | |
this.props[propName].addListener(this.animatedListener); | |
} | |
} | |
/** | |
* When the component unmounts, destroy the listener | |
*/ | |
componentWillUnmount() { | |
if (this.props[propName]) { | |
// cleanup to avoid memory leaks | |
this.props[propName].removeAllListeners(); | |
} | |
} | |
/** | |
* The name of the new prop (propName + 'Number') | |
*/ | |
propNameNumber: ?string = undefined; | |
/** | |
* listen to the animated value, and save the position as an Number | |
*/ | |
animatedListener = ({ value }: { value: number }) => { | |
if (!this.propNameNumber) return; | |
this.setState({ [this.propNameNumber]: value }); | |
} | |
/** | |
* this is an HOC: render the original component, passing in the new number prop and | |
* all the original props | |
* @returns {React.Node} - the original component | |
*/ | |
render(): React.Node { | |
if (!this.propNameNumber) return null; | |
const newProps = { [this.propNameNumber]: this.state[this.propNameNumber] }; | |
return <WrappedComponent {...newProps} {...this.props} />; | |
} | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment