Building an Animation Hook in React Native

Take a first look at how you can use React Hooks to simplify your animation logic in React Native.

Spencer Carli
Feb 22, 2019 · 3 min read

Note: At the time of recording/writing React Native 0.59 is in RC status. As such, to try it out you’ll need to specify your React Native version react-native init MyProject --version react-native@next

Second Note: Hooks are new and I’m new to them too. I may have misspoken multiple times through the video — my apologies! I’m learning them too ;)

This post was originally published on React Native School. For the most up to date article & resources please visit me there! Also, if you’re looking to level up as a React Native developer check out some of our other tutorials!

Why useRef?

The returned object will persist for the full lifetime of the component.

Since we want one animated value that we continually update we want it to persist through the full lifetime of the component, rather than being re-created each time the component updates (each time the count increments in this case).

Update #1: Avoiding Memory Leaks

Additional Resources

The final code from the video can be found below:

import React, { useEffect, useRef } from 'react';
import { View, Animated, Text } from 'react-native';

const Box = ({ backgroundColor = '#3cae6f', scale = 1 }) => (
<Animated.View
style={[
{
width: 100,
height: 100,
backgroundColor,
transform: [{ scale }],
},
]}
/>
);

const usePulse = (startDelay = 500) => {
const scale = useRef(new Animated.Value(1)).current;

const pulse = () => {
Animated.sequence([
Animated.timing(scale, { toValue: 1.2 }),
Animated.timing(scale, { toValue: 0.8 }),
]).start(() => pulse());
};

useEffect(() => {
const timeout = setTimeout(() => pulse(), startDelay);
return () => clearTimeout(timeout);
}, []);

return scale;
};

const App = ({ count }) => {
const scale = usePulse();
const scale2 = usePulse(750);

return (
<View
style={{ flex: 1, alignItems: 'center', justifyContent: 'space-around' }}
>
<Box scale={scale2} backgroundColor="#1f9cb8" />
<Text>{count}</Text>
<Box scale={scale} />
</View>
);
};

// class App extends React.Component {
// scale = new Animated.Value(1);

// componentDidMount() {
// setTimeout(() => this.pulse(), 500);
// }

// pulse = () => {
// Animated.sequence([
// Animated.timing(this.scale, { toValue: 1.2 }),
// Animated.timing(this.scale, { toValue: 0.8 }),
// ]).start(() => this.pulse());
// };

// render() {
// return (
// <View style={{ flex: 1, alignItems: 'center', justifyContent: 'space-around' }}>
// <Text>{this.props.count}</Text>
// <Box scale={this.scale} />
// </View>
// );
// }
// }

export default class Wrapper extends React.Component {
state = { count: 1 };

componentDidMount() {
setInterval(() => {
this.setState(state => ({
count: state.count + 1,
}));
}, 500);
}

render() {
return <App count={this.state.count} />;
}
}

Originally published at www.reactnativeschool.com.

React Native School

Learn to build great React Native apps.

Spencer Carli

Written by

Student. Teacher. Pizza fiend. I write about React Native, Meteor, and more. http://learn.handlebarlabs.com

React Native School

Learn to build great React Native apps.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade