Beginners Guide to React Native Animation

Introduction

React Native makes building a simple cross-platform app fun, especially if you know JavaScript. A lot can be built with components like <View> and <Text>. But they can only get you so far.

Mobile apps need some sort of animation. Unless you’re used to making animations, the jump in complexity can be daunting.

This Beginners Guide to React Native Animation aims to help you get over that initial hurdle.

Animation Basics

Before starting the basics of animation in React Native. It’s worth explaining the basics of animation itself.

Animation is the process of making the illusion of motion and the illusion of change by means of the rapid display of a sequence of images that minimally differ from each other.

Or in other words, repeatedly drawing something slightly differently, makes things look animated.
Unfortunately, we can’t load our apps with 1000s of slightly different images. That would lead to all manner of problems with size, how you interact with it etc.

So, we need our own illusions.

Illusions, aka Maths!

Don’t worry, you don’t need to be a math genius to understand this.

Let’s take the simple example of moving a red box from the top of the screen to the bottom.

render(){
	<View style={{styles.redboxTop}} />
}
…
…
const styles = StyleSheet.create({
	redboxTop: {
		position: "absolute",
		left: width / 2 - 15,
		top: 10,
		height: 30,
		width: 30,
		backgroundColor: "red"
	}
});

To draw the box at the bottom of the screen, you write some code like:

render(){
	<View style={{styles.redboxBottom}} />
}
…
…
const styles = StyleSheet.create({
	redboxBottom: {
		position: "absolute",
		left: width / 2 - 15,
		top: height - 30,
		height: 30,
		width: 30,
		backgroundColor: "red"
	}
});

The only difference here is the value assigned to the top style. It’s changed from 0 to X.

So you could animate the box by creating a loop from 0 to X and redrawing the box with the loop variable every time. As we know, in React, you get a redraw every time you call setState. So let’s redraw the box, with the top value based on state every 10ms.

constructor(props) {
	super(props);
	this.state = { top: 0 };
	this._interval = 0;
}

componentWillMount() {
	this._interval = setInterval(() => {
		if (this.state.top >= height - 30) {
			clearInterval(this._interval);
		}
		this.setState((prevState, props) => {
			return { top: prevState.top + 1 };
		});
	}, 10);
}

render() {
	return <View style={[styles.redboxAnim, { top: this.state.top }]} />;
}

const styles = StyleSheet.create({
	redboxAnim: {
		position: "absolute",
		left: width / 2 - 15,
		top: 10,
		height: 30,
		width: 30,
		backgroundColor: "red"
	}
});
React Native - For Loop Animation

React Native – For Loop Animation

It works! I’ve included the value of top so you can see it change and how the changes relate to the position of the cube.

That’s the basics of animation. Tie a variable that we control, to a style property and changed it over time.

Problem – A lot of code

That’s quite a lot of effort and code for something as simple as moving a box. Try and imagine the code you would need to do something more complex. This approach isn’t going to scale to anything much more complex.

This is where React Native Animated comes in.

Solution – React Native Animated API

The [Animated API] provides components and helpers to make our lives easier. The components are the same as the non-Animated components. But without all the JavaScript ~diffing, reconciliation~ magic.

We can also use the React Animated helpers, like Animated.Value and Animated.timing. These help with the calculations and update the native components for us.

First, instead of declaring a variable for our for loop, use Animated.Value. This is what we will tie to our style property. But instead of our code updating the value, we will let React Native Animated do it.

How does React Native Animated update values? Again, there are several helpers, but for now, we’ll keep things simple and use Animated.timing. For example, this

this.top = new Animated.Value(0);

Animated.timing(this.top, {
	toValue: height - 30,
	duration: 1500
}).start();

Which takes the value stored in this._top and updates over the course of 1500 ms to the value in `toValue’. React Native takes care of figuring out by how much top needs to change each update. So we end up with a lot less code.

All we need to do is tie that to our top CSS variable, so the complete listing of the component is:

import React, { Component } from "react";
import {
	Animated,
	AppRegistry,
	Dimensions,
	StyleSheet,
	Text,
	View
} from "react-native";

let { width, height } = Dimensions.get("window");

export default class AnimatedSquare extends Component {
	constructor(props) {
		super(props);
		this.top = new Animated.Value(0);
	}
	
	componentWillMount() {
		Animated.timing(this.top, {
			toValue: height - 30,
			duration: 1500
		}).start();
	}
	
	render() {
		return (
			<Animated.View
				style={[
					styles.redboxAnim,
					{
						top: this.top
					}
				]}
			/>
		);
	}
}

const styles = StyleSheet.create({
	redboxAnim: {
		position: "absolute",
		left: width / 2 - 15,
		top: 10,
		height: 30,
		width: 30,
		backgroundColor: "red"
	}
});
React Native - Animated Timing - Animation

React Native – Animated Timing – Animation

Again, I’ve included the value of top so you can see it change over time.

Conclusion

We’ve seen that animation is an “illusion”. It boils down to drawing slightly different images in rapid succession.

To achieve that effect in React Native (or the web for that matter), we can tie variables to style properties. Then change those variables over time, redrawing the screen as we go.

Tie a variable that we control, to a style property and changed it over time.

You’re more than welcome to do that the hard way, but React Native has some nice helpers to make it easier. In this post I used Animated.timing, but there are others.

Remember though, it boils down to changing a number over time. Then using that number to update the value of a style property.

Please let me know if I’ve made a mistake in this post. Or you think I’m missing a trick in my explanation. React Native Animated didn’t click for me till I made this realization. I hope this helps you too.

Income Report for May 2017

I’m making my income reports, including traffic numbers, public. That way, anyone thinking of starting something similar can see real world numbers. There are a lot of other sites sharing their income, so why does the world need another one?

I’m sharing the figures from month 1, which isn’t that common. Also, I can’t see many income reports from mobile app developers. So I’m hoping that this is something unique.

My hope is that these reports will inspire someone else to try something themselves. Please let me know if you think I can improve them. I’m always looking for ways to improve.

Milestone – 1 year

Wow, where has the time gone? This is the 12th monthly income report, so it’s more reflective than normal.

Starting with some numbers.

Yearly Totals

Category Total
Hours Worked 265
Profit -£36.70
Apps Released 1
App Downloads 15
  • I didn’t log hours in the first 2 months, so assumed the average from the rest of the year

So, purely from a return on investment point of view, this site has been an epic failure. How about from my original plan?

Target from June 2016

12 months ago, my main target was simple:

“By June 2017 I want to be earning an extra £10 a month”

Again, I’m nowhere near hitting that target.

So why am I still extremely happy I created this site? Very simply, it’s because the skills I’ve learned have allowed me to quit the job I no longer liked and find something I enjoy.

As for the “normal” income report…

Current Status

Last month I said that this site was being neglected. Compared to the peak of late last year (when I was unemployed) that’s probably true. However, with a change in my work routine, I’m finding it easier to spend more time on this.

I think I have to admit though, my enthusiasm for this experiment has dropped a lot.

Hours this month

As always, I track the hours I’m spending on this project. It helps me track “return on investment” and highlights how much effort is required for something like this.

Topic Hours
Income Report for April 2017 1
Studying other apps 5
How to create a local npm package of React Components 5
Updating Basic Pairs Level Over Screen 8
Updating CodeCanyon listing 2
Blog Post on Level Over Screen 3

Total Hours this month – 24

App Downloads

This is a new section for my monthly reports. I should’ve added one before, but as you will see shortly, the numbers aren’t exactly earth shattering.

App Monthly Downloads Total Downloads
Basic Pairs 5 15

As you can see, there was a peek in downloads this month. Not sure why.

Traffic for MM YY

Audience Overview - May 2017

Audience Overview – May 2017

Audience Stats - May 2017

Audience Stats – May 2017

Acquisition Overview - May 2017

Acquisition Overview – May 2017

Nothing to report for any of those graphs.

Monthly Income

Description Value
AdSense £2.60
Chitika Ads £0.10
Chitika Referal £0
TsoHost Referal £0
Amazon Associates £0

Total Income £2.60

Monthly Expenses

Description Value
Site Hosting £1.25 (£14.99 a year)

Total Expenses £1.25

Profit over time

Total Profit £2.60 – £1.25 = £1.35

Income Over Time - May 2017

Income Over Time – May 2017

Analysis

The best month, yet again, for ads on the site. It’s all luck driven though, as the number of visitors hasn’t changed.

How To Create A Local NPM package of React Components

One of the big benefits of React.js is reusable components. In fact, you’ve probably used one of the many awesome react.js components from npm. Rather than copy and paste your own components from project to project. Here’s how to create a local npm package of react components.

Useful Boilerplate

https://github.com/juliancwirko makes it easy to create a NPM Package of React Components. I wanted a package called myappincome, so I did the following:

  • Clone the repo into myappincome with git clone https://github.com/juliancwirko/react-npm-boilerplate.git myappincome
  • Remove the git repo that was cloned with cd myappincome; rm -rf .git
  • Edit package.json so the name of the package is “myappincome”
  • Initialize a new git repo with git init
  • npm install
  • Edit \src\index.js to create a very simple component like:
import React from 'react';

class MyComponent extends React.Component {

    render() {
    return (
      <div>
        FROM INSIDE MY COMPONENT
      </div>
    )
   }
};

export default MyComponent;

As you can see, not the most useful component in the world, but will demonstrate this works fine.

Let’s try it out.

Using it in a project

To keep things simple, I’ll use [Create-React-App] to demonstrate how our package can be used. The process will be similar for whatever project you’re working with.

create-react-app testlocalpackage
cd testlocalpackage
npm install --save /path/to/myappincome

You should see something very similar to this:

npm WARN prepublish-on-install As of npm@5, `prepublish` scripts will run only for `npm publish`.
npm WARN prepublish-on-install (In npm@4 and previous versions, it also runs for `npm install`.)
npm WARN prepublish-on-install See the deprecation note in `npm help scripts` for more information.

> myappincome@1.0.1 prepublish /tmp/myappincome
> babel --plugins transform-es2015-modules-umd src --ignore __tests__ --out-dir ./dist

src/index.js -&gt; dist/index.js
testlocalpackage@0.1.0 /private/tmp/testlocalpackage
└── myappincome@1.0.1 

You can see the package is called “react-npm-boilerplate” and version “1.0.1”. You can change this in package.json, but for now, I’m leaving it alone.

Now edit src\App.js to import and use our component:

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import MyComponent from 'myappincome';

class App extends Component {
	render() {
		return (
		<div className="App">
			<div className="App-header">
				<img src={logo} className="App-logo" alt="logo" />
				<h2>Welcome to React</h2>
			</div>
			<p className="App-intro">
				To get started, edit <code>src/App.js</code> and save to reload.
			</p>
			<MyComponent />
		</div>
		);
	}
}
export default App;

That’s it! Start the application with yarn start and you should see our component being rendered:

MyComponent In Create React App

MyComponent In Create React App

Multiple Components

So far, we’ve only got one component. Adding multiple components is a little trickier as we can only export 1 as default. That means we have several options. To keep this short, I’m going to show an example of adding 2 more components and the various ways they can be exported and included in an app.

Two More Components

Let’s create two news files in \src. The first called TestComponent.js:

import React from 'react';

class TestComponent extends React.Component {

    render() {
    return (
      <div>
        FROM INSIDE TEST COMPONENT
      </div>
    )
   }
};

export default TestComponent;

A second called SampleComponent.js with:

import React from 'react';

class SampleComponent extends React.Component {

    render() {
    return (
      <div>
        FROM INSIDE SAMPLE COMPONENT
      </div>
    )
   }
};

export default SampleComponent;

Finally, rename src\index.js' tosrc\MyComponent.js’. We’ll be creating a new index.js next.

Exporting multiple components

Mozilla’s article on explaining the different types of import and export is about the best I’ve come across. If you’re not comfortable with the different types, definitely go and read that before the rest of this post.

Create src\index.js with the following:

import SampleComponent from './SampleComponent';
import  MyComponent from './MyComponent';
import TestComponent from './TestComponent';

export default TestComponent;
export {MyComponent, SampleComponent};

Importing Multiple Components

Update App.js to:

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import TestComponent, {MyComponent, SampleComponent}  from 'myappincome';

class App extends Component {
	render() {
		return (
		<div className="App">
			<div className="App-header">
				<img src={logo} className="App-logo" alt="logo" />
				<h2>Welcome to React</h2>
			</div>
			<p className="App-intro">
				To get started, edit <code>src/App.js</code> and save to reload.
			</p>
			<MyComponent />
      <br />
      <SampleComponent />
      <br />
      <TestComponent />
		</div>
		);
	}
}
export default App;

Refresh the app and it doesn’t work! That’s because there’s a drawback to packaging up your components in an npm package.

Drawback

Unfortunately, any changes we make to our components in myappincome don’t show up in our app automatically. Just like when a new version of an app is released on npm.

Thankfully, it can be easily worked around by deleting the myappincome folder with rm -rf node_modules\myappincome and then running npm install again after every change.

It’s not ideal, but at least it works.

MultipleComponents in Create React App

MultipleComponents in Create React App

Conclusions

It’s now much easier to share components between all our projects and we haven’t had to install a local npm server like Sinopia.

What’s more, if at some point in the future we decide to publish our package on npm, we can.

As always, I’m not sure this is the best way to do this. It works, but if you know of a better way, please get in touch either in the comments below, or on twitter https://twitter.com/myappincome.