How to use React Spring to animate your message

Steadylearner
12 min readMar 8, 2019
Screenshot fof Animated Message with React Spring by Steadylearner

Recently, I almost built every components that I wanted for my website. I thought that it is time to learn JavaScript animations seriously before move on.

For I use React a lot for Frontend Development, I found that it would be good to learn animation packages for it. While I am searching for candidates for the purpose, I found that React Pose and React Spring interesting.

After giving some hours to read theirc documentations, I decided to use React Spring and there are two major reasons for the decision.

  1. I already used React Motion inside my project. It has similar API and concept with React Spring and it would take less time for me to learn it.
  2. It uses new React Hook api majorly and I can learn both React Spring and pratice React concepts at the same time naturally.

So I gave it a try and thought I made something very simple and easily shareable and I want to share my learning process while doing that.

Before we move on, I want to let some links to help you understand better packages used for this post. You may read their documentations first before.

[References]

  1. React API for this post
  2. React Spring Transition API
  3. Animate CSS
  4. Prop-Passer

At first, I started to use React Spring without fully understanding how React Hook API works and it didn’t work well. So I read the official documenation for it several times. After that, I found that React Spring API are just custom hooks that originate from React Hooks.

Therefore, it would be much easier if you try to understand React Hook API first for they share many aspects in common.

If you are a person who just want to learn from codes , you may visit the codesandbox example below first or here to see just the end result.

Animated message with React Spring transition API by Steadylearner

I decided to use codesandbox here for it is easy to edit and convert to Create React App projects. It is also works well for mobile device. You may find it useful to share after you follow this post and make your own version.

(I will not include how to setup React Projects in posts for there are tons of them and think it is unncessary.)

[Table of Contents]

  1. Playing with official example
  2. Make your original content
  3. How to refactor it with another components
  4. Reduce code volume with Prop-Passer
  5. Conclusion

1. Playing with official example

Photo by Irina Murza on Unsplash

Personally, I found that React Spring exampels very useful but it was not easy to understand how to use it for React projects before visitng one of its Codesandbox examples.

You may have visited the React API for this post already and seen the code snippet below.

const [toggle, set] = useState(false)
const transitions = useTransition(toggle, null, {
from: { position: 'absolute', opacity: 0 },
enter: { opacity: 1 },
leave: { opacity: 0 },
})
return transitions.map(({ item, key, props }) =>
item
? <animated.div style={props}>😄</animated.div>
: <animated.div style={props}>🤪</animated.div>
)

I thought that “Ok. It would be easy and fun to follow for it uses imojis that I use in my daily life at chat apps.” but only copying and pasting it to the project wouldn’t work.

// Please, visit the index_start.js file at codesandbox if you 
// want to understand code snippet here better.
import React, { useState } from 'react';
import ReactDOM from 'react-dom';
import { animated, useTransition } from 'react-spring';
import './styles.css';
function Test() {const [toggle, setMessage] = useState(false)
const transitions = useTransition(toggle, null, {
from: { position: 'absolute', opacity: 0 },
enter: { opacity: 1 },
leave: { opacity: 0 },
})
return transitions.map(({ item, key, props }) =>
item
? <animated.section key={key} onClick={() => setMessage(!toggle)} style={props}>😄</animated.section>
: <animated.section key={key} onClick={() => setMessage(!toggle)} style={props}>🤪</animated.section>
)
}
ReactDOM.render(<Test />, document.getElementById('root'))// Just for beginners!, We set business logic for toggle and setMessage and pass what we want to do inside onClick for what we want to with toggle(state) like we do with setMessage(!toggle)

For this example, There are some modifications.

  1. I used section instead of div for I prefer to use it and include key for props as key={key}. There was no explicit explanation why it is included in destructured arguments in transition.map API.

(After receiving warning from React that there is no keys for some React elements, I found that I have to use it that way to solve the problem. )

2. I included onClick method for animated.section components after assuming that they should be affected by some states(here it is toggle) and it worked.

It is likely that item in code snippet refers React Components passed inside transitions.map but I couldn’t find the explanation for that.

Maybe we should read the source code or find more information but what is the most important is that we have working example and now we can tweak it.

You may visit the Codesandbox example and use index_start.js that I prepared for you to verifiy it.

2. Make your original content

Photo by Stanley Dai on Unsplash

We made a first step to learn how to use React Spring in the privesous process. It is time to be creative and make your original contents. I will help you to do it easily while explaning the work I have done for the end result.

In the original examples, I thought that it would be better to use some messages with ? marks before transition animation happen and after that with messages that I want to use.

The entire code snippet after this process would be like below.

// Please, visit the index_static.js file at codesandbox if you 
// want to understand code snippet here better.
import React, { useState } from 'react';
import ReactDOM from 'react-dom';
import { animated, useTransition } from 'react-spring';
import './styles.css';
function AnimatedMessage() {const [toggle, set] = useState(false)
const transitions = useTransition(toggle, null, {
from: { position: 'absolute', opacity: 0 },
enter: { opacity: 1 },
leave: { opacity: 0 },
})
// !importantconst beforeMessage = "You know what?";
const afterMessage = "I love you";
return transitions.map(({ item, key, props }) =>
item
? <animated.section key={key} onClick={() => setMessage(!toggle)} style={props}> <span className="animated pulse delay-1s hover hover--red cursor-pointer transition--default"> {beforeMessage} </span>
</animated.section>
: <animated.section key={key} onClick={() => setMessage(!toggle)} style={props}> <> {afterMessage} <span className="animated heartBeat infinite">💗</span>
</> </animated.section>
)
}
ReactDOM.render(<AnimatedMessage />, document.getElementById('root'))// In the page, I only included css necessary from original
// example and wrote many css classes to work for only single
// functionality
// Therefore, It ended up having many css classes
// for each components. It is just a difference of writing code
// styles and I will show how to remove repeating classes with
// React NPM package prop-passer
// For someone who read the source code, I think that a little
// explantion will help you understand the intention of CSS.
// 1. I used hover--red for the color of it is similar to 💗
// 2. Pulse to show that there is something waiting and it is also // similar to heartBeat(for the imoji)
// 3. delay-1s to not to show animation instantely for someone
// with low internet speed.

In this process, I wanted to use animate css with React Spring. After many times of trial and errors, I found some fomrat that animate CSS and React Spring work together without problem.

The code snippet above became a little bit complicated because of CSS. But You don’t have to care about that much for this is not major point for this post.

The important thing here is that we refactor the function a little bit to get dynamic data later. You may read simplified code snippet below.

// className and other logics are omitted intentionally hereconst beforeMessage = "You know what?";
const afterMessage = "I love you";
// inside function AnimatedMessage<animated.section key={key} onClick={() => setMessage(!toggle)} style={props}> <span> {beforeMessage} </span>
</animated.section>
: <animated.section key={key} onClick={() => setMessage(!toggle)} style={props}> <> {afterMessage} <span>💗</span>
</> </animated.section>
)
}

Ok, the entire code snippet above would work without problem. It may have some meaning for someone you care for to show how you think of them with simple animations.

At this point, You may use your own messages, images, imojis etc to make your own message and share them with others easily in the given format not knowing a lot about html, css and JavaScript.

3. How to refactor it with another components

Image of app state for this post by Steadylearner

Until now, the option for user is limited to click the message “You know what?” to find your real message “I love you 💗”.

We can do better and make more options for users to make your simple JavaScript app become more interesting.

(If you have read the official React documenation well, You would know that the API is just a function and you can easily use return value from it and pass arguments easily also. We will use this concept for this phase.)

While I am preparing the code used here, I found that it would be good to give langauge options for the app and some link for my website. It can also show that who wrote the code also.

For that, we will separate logic for switch animation, then make logic for language options and lastly make some React Components for layout.

Let’s start with seprate logic to toggle animation.

// use before and after instead of beforeMessage and afterMessage for simpicity and generosity.
// It doesn't have any static data from the programmer anymore.
// Please, visit index_without_propasser.js at Codesandboxfunction AnimatedMessage({ before, after }) {
const [toggle, setMessage] = useState(false)
const transitions = useTransition(toggle, null, {
from: { position: 'absolute', opacity: 0 },
enter: { opacity: 1 },
leave: { opacity: 0 }
})

return transitions.map(({ item, key, props }) =>
item ? (
<animated.section key={key} onClick={() => setMessage(!toggle)} style={props}>{after}</animated.section>
) : ( <animated.section key={key} onClick={() => setMessage(!toggle)} style={props}> {before} </animated.section>
)
)
}

It has become function with only logics and we can pass arguments and also use return values in other functions, classes etc. Then we will prepare another functional components that will use the AnimatedMessage inside.

Minified example without CSS by Steadylearner

It has become difficult to keep inside code snippet so I prepared version without some clssasName to explain better.

The logic here is almost same for the AnimatedMessage functional components. We just use other name for variables to make it easy to understand and use tenary operator ? to send different data depending on the state of lang we define inside useState.

With some more components and similiar logics, You can show separate message for languages you want.

With these simple code snippets, You can now make your own versions to share with others. I hope you can make better than the image inside the title image.

If you happen to read without much experience in programming, You may visit the Codesandbox example and tweak href part for the page you want to send other person, src part to use your preferred image and you can use your own messages.

The entire code snippet should be working and there would be no serious difficulty. But code snippet became a little bit long and I want you help you to know how to reduce code snippet size in the next process with Prop-Passer.

4. Reduce code volume with Prop-Passer

Prop Passer Image made with ImageMagik and Python by Steadylearner

Prop-Passer is very small library that I prepared to extract common props and components from repeating code snippets from others. You may not need this library much if you already coding while not repeating yourself.

So you may skip this part if you already found what interested you.

But you would find it useful in some cases like the code snippets with many classNames are common among components.

Before I introduce Prop-Passer. Let’s separate AnimatedMessage function inside other files and it will be

// AnimateMessage.jsimport React, { useState } from 'react';
import { animated, useTransition } from 'react-spring';
function AnimatedMessage({ before, after }) {
const [toggle, setMessage] = useState(false)
const transitions = useTransition(toggle, null, {
from: { position: 'absolute', opacity: 0 },
enter: { opacity: 1 },
leave: { opacity: 0 }
})

return transitions.map(({ item, key, props }) =>
item ? (
<animated.section key={key} onClick={() => setMessage(!toggle)} style={props}>{after}</animated.section>
) : ( <animated.section key={key} onClick={() => setMessage(!toggle)} style={props}> {before} </animated.section>
)
)
}
export default AnimatedMessage;// Inside index.jsimport AnimatedMessage from "./AnimatedMessage";// Remove duplicate AnimateMessage functiona components

It would be normal for React Developers to end the process at this moment.

But we are repeating

key={key} onClick={() => setMessage(!toggle)} style={props}It is exactly the same inside animated.section component.

So you may think that extracting them from the React Component would be difficult. But it isn’t. Let’s use Prop API from Prop-Passer for that first.

I will show you code snippet and you will understand better what happend.

// AnimateMessage.js with Prop from prop-passerimport React, { useState } from 'react';
import { animated, useTransition } from 'react-spring';
import { Prop } from "prop-passer";function AnimatedMessage({ before, after }) {
const [toggle, setMessage] = useState(false)
const transitions = useTransition(toggle, null, {
from: { position: 'absolute', opacity: 0 },
enter: { opacity: 1 },
leave: { opacity: 0 }
})

return transitions.map(({ item, key, props }) =>
// Extract common parts with Prop Api from prop-passer
// It is separated from components and became resuable also.
const AnimationProp = Prop({
key,
onClick: function () {
setMessage(!toggle);
},
style: props,
});


if (item) {
return <AnimationProp>
<animated.section>
{after}
</animated.section>
</AnimationProp>
} else {
return <AnimationProp>
<animated.section>
{before}
</animated.section>
</AnimationProp>
}
}
)
}
// key={key} onClick={() => setMessage(!toggle)} style={props}
// is resuable with AnimationProp and what you need to do is just wrap the components that you want to pass props.
export default AnimatedMessage;

You may think that you don’t need to use it just to extract common props inside two components.

So let’s use it for the AnimatedMessageWithOption functional components.

You may have found that className “hover, cursor-pointer, transition — default” are common inside the components. We will extract it to separate files to make the index.js to have less length.

It is good to extract codes as much as possible at each trial. So for this case I will introduce PropPasser that does similar function like Prop before.

We will make NavClassPasser with PropPasser API like the code snippet below.

// Read index.js at Codesandbox to help you understand better
// You should use either class or className for synchronicity when // you want to use class or className with prop-passer API
// You may use always className if you don't like warnings from
// the console
const NavClassPasser = PropPasser({
className: "hover cursor-pointer transition--default",
})({className: "flex flex--row"})("nav");
// extract common className "hover cursor-pointer transition--default// extract wrapper <nav className="flex flex--row"></> also at the same time

Then we will use it a wrapper to pass classNames for childeren components

// Read index.js at CodeSandbox and compare it with index_withou_prop_passer.js<ClassPasser>
<a
className="
right-auto
margin-left-half
flex--center
x-outline
"
href="https://www.steadylearner.com/about"
title="External link to www.steadylearner.com"
alt="External link to www.steadylearner.com"
target="_blank"
rel="noopener noreferrer"
>
Rest of the CodeSnippet here.......
</ClassPasser>

You may found that you don’t have to repeat common classNames anymore and you can also extract warpper components with their props using PropPasser API from Prop-Passer.

For the PropPasser used here is just simple wrapper element and passing the same className to children elements, we can still extract it to external fils as it is in PropPassers.js inside the CodeSandbox example.

5. Conclusion

YouTube Heart Image made with CSS, Python and ImageMagik by Steadylearner

We started from integrating React Spring transition API for our project and passsed various phases to reach the end result. I also included how to use Prop-Passer APIs to help you reduce the code sizes from this project.

The entire code snippet itself would be helpful for you to share with your friends and you may make your own version.

Before I wrote this post, It was difficult to find practical examples except from the author of the package. I hope that it can be starting point for you to learn React Spring and React Hook API also.

You may want to share your message easily with others. It would work well already at mobile well with help from Codesandbox and I would write how to include social media share for React App after this post.

I am planning to write more posts for this platform before I find how to handle metadata for the React, Python and Rust website www.steadytlearner.com and I will write post for that also.

If you want to make React Components to share your animaiton, Please visit How to use React-Share with Prop-Passer.

Thanks and please share this post with others.

p.s

  1. Did you like my coding style? Please, send messages via LinkedIn or Twitter. I am also the writer of React Package prop-passer
  2. I am the author of www.steadylearner.com and it is mobile friendly also. You may visit it.

I am not a native English speaker. When some words don’t make sense, grammar problems etc. Please leave a comment below. I will read this post again and edit them right away.

--

--