React Native Animation with Boolean

Kenneth Cheung
< />
Published in
3 min readMay 6, 2018
Photo by Caspar Camille Rubin on Unsplash

Animation in React Native

Animated API is an awesome approach in React Native to create engaging animation.

It works by making an animated value tween, then map the animated value to the style which you want to animate. If you are not familiar to Animated, please check out the documentation.

Control Animation by boolean?

Sometimes, we want to animate our component with boolean, but Animated API does not provide it by default. It is a little bit inconvenient. For instance, your want to have a fade in, fade out effect on your button. The implementation may looks something like the following,

Container (before)

// ...class MyContainer extends React.Component {
// ...
toggleBtn() {
if (this.state.btnActive) {
this.setState({ btnActive: false });
Animated.spring(
this.state.animatedValue,
{
duration: 300,
toValue: 0,
friction: 10
}
).start();
} else {
this.setState({ btnActive: true });
Animated.spring(
this.state.animatedValue,
{
duration: 300,
toValue: 1,
friction: 10
}
).start();
}
}
render() {
return (
// ...
<Animated.View
style={ {
opacity: this.state.animateValue.interpolate({
inputRange: [0, 1],
outputRange: [0, 1]
}),
} }
>
<Button
title="I am a button"
/>
</Animated.View>
// ...
);
}
}

It is not ideal for two reasons.

  1. There are two tasks in order to toggle the button
  2. The animation implement details are in the Container file

Animated Higher-Order Components

Creating a animatedHOC may address the problem. The extra layer can abstract the detail for toggling a button with animation, So that the Container no longer to care about how the button should be animated.

animatedHOC deal with all the animation value tween logic as following,

import React, { Component } from ‘react’;
import {
Animated,
InteractionManager
} from ‘react-native’;

export default function animatedHOC(WrappedComponent) {
return class AnimatedCtrl extends Component {
constructor(props) {
super(props);
this.state = {
active: props.active,
animateValue: new Animated.Value(0)
};
}
componentWillReceiveProps(nextProps) {
if (this.state.active === nextProps.active) return;
Animated.spring(
this.state.animateValue,
{
duration: this.props.duration,
// Components which are wrapped by the HOC can decide what
// animation to implement based on the animateValue
// between 0 and 1.
toValue: nextProps.active ? 1 : 0,
friction: 10
}
).start();
this.setState({
active: nextProps.active
});
}
render() {
return (<WrappedComponent
{ ...this.props }
animateValue={ this.state.animateValue }
/>);
}
};

FadeAnimationBtn receives animateValue props to implement corresponding animation.

Container (after)

import React from ‘react’;
import {
View,
Animated,
Button,
Text
} from ‘react-native’;
import Button from 'path/to/myButton';
import animatedHOC from ‘../animatedHOC’;
export const FloatBtn = ({
onPress,
title,
animateValue
}) => (
<Animated.View
style={ {
opacity: animateValue.interpolate({
inputRange: [0, 1],
outputRange: [0, 1]
}),
} }
>
<Button
onPress={ onPress }
title={ title }
/>
</Animated.View>
);
export default animatedHOC(FloatBtn);

Notice that FadeAnimationBtn must be wrapped by animatedHOC since FadeAnimationBtn needsanimatedValue as its props.

Container

// ...
import FadeAnimationBtn from 'path/to/FadeAnimationBtn';
class MyContainer extends React.Component {
// ...
toggleBtn() {
this.setState({
btnActive: !this.state.btnActive
});
}
render() {
return (
// ...
<FadeAnimationBtn
active={ this.state.btnActive }
title="I am a Button"
>
// ...
);
}
}

By this approach we can implement boolean animation much cleaner. The Container only take care of the state of the button.

Above is just the minimal implementation. You can enhance the AnimatedHOC by adding InteractionManager or anything you want. You also can add other transition effect based on the animatedValue.

Conclustion

Higher-Order components is a powerful concept to make our code more concise and maintainable by separating the duplicate part and concern to the component. I hope this article helps, thanks!

--

--