DEV Community

Cover image for Introduction to React Motion
Brian Neville-O'Neill
Brian Neville-O'Neill

Posted on • Originally published at blog.logrocket.com on

Introduction to React Motion

Written by Gaurav Singhal✏️

React Motion is an animation library for React applications that makes it easy to create and implement realistic animations. In this guide, we’ll demonstrate how to install the library and share some basic tips to help you build natural-looking, physics-based animations for your React projects.

Installing React Motion

Create a new React project by running:

npx create-react-app intro-react-motion
Enter fullscreen mode Exit fullscreen mode

To install React Motion, run the following command inside your project root.

npm i react-motion
Enter fullscreen mode Exit fullscreen mode

Understanding the exports

The react-motion library exports the following.

  • spring — A helper function that dictates how the component animates
  • presets — An object of predefined animation properties
  • Motion — A component that is used to animate a component
  • StaggeredMotion — A component that is used to animate components whose animation depends on each other
  • TransitionMotion — A component that is used to animate the mount and unmounts of components

For the sake of brevity, this guide will focus on spring, presets, and Motion.

LogRocket Free Trial Banner

Helpers: spring() and presets

The spring() helper function defines how to animate from the initial style value to the destination value. It takes in two arguments: the value and an option animation config parameter.

For example, spring(10, { stiffness: 130, damping: 42 }) animates the value to 10 with a stiffness of 130 and damping of 42. stiffness and damping are animation properties that define the animation’s behavior. Don’t worry — it’s normal not to understand how these properties work.

The presets properties are used as the animation configuration. For example, spring(25, presets.wobbly). Other preset values include presets.gentle, presets.noWobble, presets.stiff.

The <Motion /> component

The <Motion /> component takes in two props: defaultStyle and style. The defaultStyle prop defines the initial values of the style object. The style prop is an object that defines the style values at any given point. The values of the style prop are determined using the spring() helper function. If the defaultStyle is the original style, then style is the final style that the components animate to.

The <Motion /> component expects a function as its child prop, which means it uses the render prop pattern. The function receives an interpolated style object, which contains the style value at any given time until the animation is completed.

<<Motion
  defaultStyle={{
    scale: 0,
    translateX: -300
  }}
  style={{
    scale: spring(1),
    translateX: spring(0, presets.stiff)
  }}
>
  {interpolatesStyles => <>{/* React Component */}</>}
</Motion>
Enter fullscreen mode Exit fullscreen mode

React Motion in action

Let’s look at a basic example.

At the top of your component file, import Motion, spring, and presets from the react-motion library to use them in your component.

import { Motion, spring, presets } from "react-motion";
Enter fullscreen mode Exit fullscreen mode

Create an <h1> element in the component that will be animated inside App.js.

// ...
function App() {
  return (
    <div className="App">
      <div>
        <h1>Basic Animation Example</h1>
      </div>
    </div>
  );
}
// ...
Enter fullscreen mode Exit fullscreen mode

Now wrap your component with the <Motion /> component and return the <h1> component from the render prop function. Pass { opacity: 0, translateY: 30 } in the defaultStyle prop. In the style prop, use the spring() helper function to interpolate the style values.

// ...
<Motion
  defaultStyle={{
    opacity: 0,
    translateY: 30
  }}
  style={{
    opacity: spring(1),
    translateY: spring(0, presets.wobbly)
  }}
>
  {interpolatedStyles => (
    <div
      style={{
        transform: `translateY(${interpolatedStyles.translateY}px)`,
        opacity: interpolatedStyles.opacity
      }}
    >
      <h1>Basic Animation Example</h1>
    </div>
  )}
</Motion>
// ...
Enter fullscreen mode Exit fullscreen mode

Here’s the final code:

import React from "react";
import "./styles.css";
import { Motion, spring, presets } from "react-motion";

function App() {
  return (
    <div className="App">
      <Motion
        defaultStyle={{
          opacity: 0,
          translateY: 30
        }}
        style={{
          opacity: spring(1),
          translateY: spring(0, presets.wobbly)
        }}
      >
        {interpolatedStyles => (
          <div
            style={{
              transform: `translateY(${interpolatedStyles.translateY}px)`,
              opacity: interpolatedStyles.opacity
            }}
          >
            <h1>Basic Animation Example</h1>
          </div>
        )}
      </Motion>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Run the following command to see the above code in action.

npm start
Enter fullscreen mode Exit fullscreen mode

The animation will start as soon as the component mounts on to the DOM. Now let’s see how you can also trigger the animation with a button click.

Triggering animation using a button

Using state, you can add style dynamically to interpolate the style values. In a variable, store the initial style for the animation.

function App() {
  const [startAnimation, setAnimation] = useState(false);
  const initialStyle = { opacity: 0, translateY: 30 };
  // ...
}
Enter fullscreen mode Exit fullscreen mode

In the <Motion /> component, you don’t have to specify the defaultStyle prop because the style prop is going to change dynamically.

// ...
<Motion
  style={
    startAnimation
      ? {
          opacity: spring(1),
          translateY: spring(0, presets.wobbly)
        }
      : initialStyle
  }
>
  {interpolatedStyles => (
    <div
      style={{
        transform: `translateY(${interpolatedStyles.translateY}px)`,
        opacity: interpolatedStyles.opacity
      }}
    >
      <h1>Triggered Animation</h1>
    </div>
  )}
</Motion>
// ...
Enter fullscreen mode Exit fullscreen mode

Add two buttons: one to trigger the animation and another to reset the animation.

// ...
<button onClick={() => setAnimation(true)}>Trigger Animation</button>
<button onClick={() => setAnimation(false)}>Reset Animation</button>
// ...
Enter fullscreen mode Exit fullscreen mode

When the startAnimation state is set to true, the style prop will get the initial style values. When it sets to false, the style prop will have the final values.

Your App.js should look as follows.

import React, { useState } from "react";
import "./styles.css";
import { Motion, spring, presets } from "react-motion";

export default function App() {
  const [startAnimation, setAnimation] = useState(false);
  const initialStyle = { opacity: 0, translateY: 30 };
  return (
    <div className="App">
      <Motion
        style={
          startAnimation
            ? {
                opacity: spring(1),
                translateY: spring(0, presets.wobbly)
              }
            : initialStyle
        }
      >
        {interpolatedStyles => (
          <div
            style={{
              transform: `translateY(${interpolatedStyles.translateY}px)`,
              opacity: interpolatedStyles.opacity
            }}
          >
            <h1>Triggered Animation</h1>
          </div>
        )}
      </Motion>
      <button onClick={() => setAnimation(true)}>Trigger Animation</button>
      <button onClick={() => setAnimation(false)}>Reset Animation</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Using React Motion with styled-components

You can use react-motion with any other UI library for React. Let’s see how you can use react-motion with the styled-components library.

Install styled-components by running the following command inside your project root.

npm i styled-components
Enter fullscreen mode Exit fullscreen mode

Create the styled <Title /> component as follows.

// ..
import styled from "styled-components";

const Title = styled.h1`
  color: #007bff;
  font-size: 32px;
  ${props =>
    `transform: translateY(${props.translateY}px); 
   opacity: ${props.opacity};
  `}
`;

// ..
Enter fullscreen mode Exit fullscreen mode

Similar to the above examples, return the <Title /> component from the render prop function. Pass the interpolated values as props to the <Title /> component.

<Motion
  style={
    startAnimation
      ? {
          opacity: spring(1),
          translateY: spring(0, presets.wobbly)
        }
      : initialStyle
  }
>
  {interpolatedStyles => (
    <Title
      opacity={interpolatedStyles.opacity}
      translateY={interpolatedStyles.translateY}
    >
      Triggered Animation
    </Title>
  )}
</Motion>
Enter fullscreen mode Exit fullscreen mode

Your complete App.js should look as follows.

import React, { useState } from "react";
import "./styles.css";
import { Motion, spring, presets } from "react-motion";
import styled from "styled-components";

const Title = styled.h1`
  color: #007bff;
  font-size: 32px;
  ${props =>
    `transform: translateY(${props.translateY}px); 
   opacity: ${props.opacity};
  `}
`;

export default function App() {
  const [startAnimation, setAnimation] = useState(false);
  const initialStyle = { opacity: 0, translateY: 30 };
  return (
    <div className="App">
      <Motion
        style={
          startAnimation
            ? {
                opacity: spring(1),
                translateY: spring(0, presets.wobbly)
              }
            : initialStyle
        }
      >
        {interpolatedStyles => (
          <Title
            opacity={interpolatedStyles.opacity}
            translateY={interpolatedStyles.translateY}
          >
            Triggered Animation
          </Title>
        )}
      </Motion>
      <button onClick={() => setAnimation(true)}>Trigger Animation</button>
      <button onClick={() => setAnimation(false)}>Reset Animation</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Regardless of which library you are using, react-motion will work as long as the library supports custom styling.

If you encounter errors, depreciated warnings, or things that don’t run as expected, revert to the original versions of these libraries by replacing your dependencies inside package.json file with the following versions.

//...

"dependencies": {
    "@testing-library/jest-dom": "^4.2.4",
    "@testing-library/react": "^9.5.0",
    "@testing-library/user-event": "^7.2.1",
    "react": "^16.13.0",
    "react-dom": "^16.13.0",
    "react-motion": "^0.5.2",
    "react-scripts": "3.4.0",
    "styled-components": "^5.0.1"
 }

//...
Enter fullscreen mode Exit fullscreen mode

Then run:

npm i
Enter fullscreen mode Exit fullscreen mode

This will install the exact same dependencies on which these examples were tested.

Conclusion

React Motion is one of the easiest animation libraries out there for animating components in React. This was just a brief introduction to the react-motionlibrary. As a next step, I would recommend looking into components such as <StaggeredMotion /> and <TransitionMotion />, which are similar to the <Motion /> component but have an advanced implementation for more complex animations.


Full visibility into production React apps

Debugging React applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

Alt Text

LogRocket is like a DVR for web apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps — start monitoring for free.


The post Introduction to React Motion appeared first on LogRocket Blog.

Top comments (0)