How to add React animation on state change

Ever since I’ve started front-end development, creating a UI animation after some JavaScript event has always been a thing.

In the past, jQuery made it really simple to achieve this goal.

But, since jQuery is no longer cool, and we’re moving towards other libraries, performing animations has been a bit more challenging.

In React, manipulating the DOM directly is a big no no.

We must use React state, and let state influence the output of the render.

Let’s take a look at how this is done.

You can use CSS classes to animate in React

You can surely do animations with pure JavaScript, but my rule of thumb is:

If you can do it with CSS, than pick that!

Let’s start by creating our React component first.


import React, { useState } from 'react';
import classNames from 'classnames';
import styles from './App.module.css';

const App = () => {
  const [animate, setAnimate] = useState(false);

  const handleClick = () => setAnimate(!animate);

  return (
    <button
      onClick={handleClick}
      className={classNames(
        styles.animate,
        animate && styles.grow
      )}>
      Grow this link
    </button>
  );
}

export default App;

I’ll go over a breakdown from the code above.

In the first few lines of code, I’m importing a couple modules, and my CSS stylesheet into my React component.

Inside my functional React component, I’m creating a new state property called, animate. The state property animate will equal true or false, and determines if the HTML button element will get a class named, grow.

I’m also creating a new function to handle the click event of the button element.

The handleClick() function will toggle true or false for the animate state property.

Now let’s take a look at the the CSS file, App.module.css.


button {
  padding: 8px 16px;
  cursor: pointer;
}

.animate {
  transition: transform .35s ease-in-out;
}

.animate.grow {
  transform: scale(1.5);
}

That’s it! The output should be when the button gets clicked it grows. When it gets clicked again, it shrinks back to normal size.

Using React transitions animation library

Another option to add animation to your React component is by using a node module called, React Transition Group.

React Transition Group is designed to mount and unmount a React component over time with animation in mind.

Let’s review how to use the Transition component that is provided by the library.


import { Transition } from 'react-transition-group';
import Modal from './Modal';

const defaultStyles= {
  transition: `opacity 300ms ease-in-out`,
  opacity: 0,
};

const transitionStyles = {
  entering: { opacity: 1 },
  entered:  { opacity: 1 },
  exiting:  { opacity: 0 },
  exited:  { opacity: 0 },
};

const App = () => {

  const [showModal, setShowModal] = useState(false);

  const handleClick= () => setShowModal(!showModal);

  return (
    <>
        <button onClick={handleClick}>Show modal</button>
        <Transition in={showModal} timeout={300}>
          {state => (
            <Modal
              title="Transition alert"
              styles={{
                ...defaultStyles,
                ...transitionStyles[state]
              }}
              onClose={handleClick}/>
          )}
        </Transition>
    </>
  );
}

At the top of the code I’m importing react-transition-groups, and my custom modal component.

Right underneath the imports, I’ve created 2 variables.

  • defaultStyles – Defines some basic styles for my modal.
  • transitionStyles – Defines styles for each 4 states that the Transition component goes through.

Those 4 states are:

  • entering
  • entered
  • exiting
  • exited

Inside my App React component, I’m creating a new state property with useState().

The state property, showModal, will be responsible for influencing the the Transition component when to go through it’s phases.

Let’s see how and where I’m using showModal.


<transition in="{showModal}" timeout="{300}">
  //... children
</transition>

In the code example, I’m providing 2 props to the component.

  • in – When the value is true, it goes from “entering” to “entered”. When the value is false, it goes from “exiting” to “exited”
  • timeout – The duration of the transition.

Let’s take a look at what I’m passing through as a child component.


{state => (
  <Modal
    title="Transition alert"
    styles={{
      ...defaultStyles,
      ...transitionStyles[state]
    }}
    onClose={handleClick}/>
)}

You can pass a function that returns a React JSX node element.

That function provides an argument that holds the value of current state that the Transition component is in.

I’m using the argument value to add the right transition styles, that I defined earlier in the code.

If you’re interested in seeing the code, go to the GitHub example.

Related articles:

I like to tweet about ReactJS and post helpful code snippets. Follow me there if you would like some too!