How to make a confetti cannon with React Spring
Tags: react, javascript, tutorial
Published: 2020-01-09 18:01:17

---
title: How to make a confetti cannon with React Spring
published: true
date: 2020-01-06 14:00:05 UTC
tags: react,javascript,tutorial
canonical_url: https://blog.logrocket.com/how-to-make-a-confetti-cannon-with-react-spring/
cover_image: https://thepracticaldev.s3.amazonaws.com/i/sovg3qo345l9vjrtor4f.png
---
**Written by [Joshua Saunders](https://blog.logrocket.com/author/joshua-saunders/)**✏️

You know what everybody loves in their daily lives? A little validation, a little pat on the back, a little celebration — and a little confetti.

In this tutorial, you’ll learn how to implement a confetti cannon that can fire off of any element using React Spring from scratch. No previous React Spring experience required! The only prerequisite is a basic understanding of React and hooks.

![Confetti Cannon Built With React Spring](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2020/01/react-spring-confetti-finished.gif?resize=430%2C245&ssl=1)

If you want to jump ahead, you can skip to the [completed CodeSandbox example](https://codesandbox.io/s/confetti-complete-1ntnk).

Note: this tutorial uses [`styled-components`](https://dev.to/bnevilleoneill/what-s-new-in-styled-components-5-0-38gb). If you’ve never used `styled-components` before, don’t sweat it. It’s a powerful library for inline styling of React components, but it’s very readable, so you’ll get the gist of it just by looking at the code.

## Game plan

When I’m starting to implement something I’ve never seen before, I like to break it down into phases, starting with the core pieces, then polish afterward. We’ll attack this project step by step:

1. Get something showing up on the page
2. Set up React Spring
3. Write some basic psuedo-physics helpers
4. Anchor a single dot
5. Get many dots moving like they’re being fired from a confetti cannon
6. Add variation to confetti pieces, such as different shapes, colors, and sizes

Let’s get started!

[![LogRocket Free Trial Banner](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2017/03/f760c-1gpjapknnuyhu8esa3z0jga.png?resize=1200%2C280&ssl=1)](https://logrocket.com/signup/)

## 1. Something on the page

First, let’s make up a little app. We’ll make it a to-do app and set it to fire confetti from the checkbox when you complete an item.

![Basic To-Do App to Demonstrate How to Build a Confetti Cannon in React Spring](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2020/01/react-spring-confetti-step-1.gif?resize=430%2C245&ssl=1)

Now, let’s add a single confetti dot, which we’ll play with for the next few steps of this tutorial.

```jsx
const StyledConfettiDot = styled.svg`
  position: absolute;
  will-change: transform;
`;
const Dot = () => (
  <StyledConfettiDot>
    <circle cx="5" cy="5" r="5" fill="blue" />
  </StyledConfettiDot>
);
```

## 2. React Spring setup

React Spring is the animation library we’ll be using in this tutorial. It’s a unique library that takes the stance that animations powered by springs rather than keyframes look more natural. Instead of specifying how long an animation is and what changes occur at what time, you specify the tension, friction, and mass of the spring, as well as the start and end values of the animation, and let React Spring figure out how they relate to the spring.

Let’s get React Spring set up with our confetti dot. Run either of the following.

- `npm install react-spring`
- `yarn add react-spring`

Add the following import to `ConfettiDot.js.`

```jsx
import { animated, config, useSpring } from 'react-spring';
```

- `animated` is used to wrap existing components to allow them to use `react-spring`
- `config`s are the preset spring configs that ship with `react-spring` (we’ll be using the `default` config)
- `useSpring` is one of the main exports from `react-spring` (there is a handful of other exports, but we’ll be focusing on `useSpring`)

`ConfettiDot` enabled with `react-spring` looks like this:

```jsx
const AnimatedConfettiDot = animated(StyledConfettiDot);
const Dot = () => {
  const { y } = useSpring({
    config: config.default,
    from: { y: 0 },
    to: { y: -50 }
  });
  return (
    <AnimatedConfettiDot
      style={{
        transform: y.interpolate(yValue => `translate3d(0,${yValue}px,0)`)
      }}
    >
      <circle cx="5" cy="5" r="5" fill="blue" />
    </AnimatedConfettiDot>
  );
};
```

We’ve used `animated` to wrap our `StyledConfettiDot` component. All we have to do is call `animated(<component>)`.

`useSpring` takes an object with various properties. First, a `config` object — we’ll use the `default` one shipped with `react-spring` since it has no bounceback. Next, a `from` object that states arbitrary initial values, followed by a `to` object that states matching end values. The whole hook returns an object that matches the `from` and `to` objects. In this example, we’ve set a `y` initial and end value, and we’re destructing the result to get the `y` animated value.

Instead of using `ConfettiDot` or `StyledConfettiDot` in the render, we’re now using `AnimatedConfettiDot`, the result of the `animated` call.

In the `style` attribute of `AnimatedConfettiDot`, we use the result of the objects in `useSpring` to turn the values into valid style values.

Let’s break down the `style` attribute in more detail. Firstly, we’re using the `style` attribute instead of props because when the values change, since it’s using `animated`, it’ll just change the DOM element’s style values as opposed to causing a rerender in React. That means you can have complex animations fully on only one render. Without this, performance would be extremely slow.

Secondly, we’re using the `interpolate` function on `y` to convert it into a real string value. For values that are already equal to their final style value, such as a color or percentage value, you wouldn’t need to use `interpolate`. We’ll demonstrate this later on.

![Basic To-Do App to Demonstrate the interpolate Function in React Spring](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2020/01/react-spring-confetti-interpolate-function.gif?resize=430%2C245&ssl=1)

## 3. Pseudo-physics

While a circle moving upward is pretty fun, we want it to look like it’s firing out of a confetti cannon. To accomplish this, we’re going to make some pseudo-physics.

- When the confetti fires out of the cannon, it has a high velocity
- The confetti slows down quickly
- Eventually, gravity overtakes its velocity and it begins to fall back down

We’ll use `react-spring` to simulate the confetti’s velocity at time _t_. Let’s make a spring that goes from 100 to 0.

```jsx
const { upwards } = useSpring({
  config: config.default,
  from: { upwards: 100 },
  to: { upwards: 0 },
});
```

Let’s pretend this velocity represents pixels per second — so, starting at 100 pixels per second to 0 pixels per second.

To actually use this to move the confetti dot, we’ll do the following.

```jsx
const initialY = 0;
let totalUpwards = 0;
const startTime = new Date().getTime() / 1000;
let lastTime = startTime;

return (
  <AnimatedConfettiDot
    style={{
      transform: upwards.interpolate(upwardsValue => {
        const currentTime = new Date().getTime() / 1000;
        const duration = currentTime - lastTime;
        const verticalTraveled = upwardsValue * duration;
        totalUpwards += verticalTraveled;
        lastTime = currentTime;

        return `translate3d(0, ${initialY - totalUpwards}px, 0)`;
      })
    }}
  >
    <circle cx="5" cy="5" r="5" fill="blue" />
  </AnimatedConfettiDot>
);
```

This is a fun trick. Since `interpolate` is called on every tick of `react-spring`, we’re calculating the time between the current tick and the last tick, getting the current velocity, and calculating the distance traveled (velocity \* duration since last tick), then adding that to the total distance traveled in `totalUpwards`. Then we use `totalUpwards` as the resulting translated value (using subtraction, since positive upward movement is negative `y` axis movement in the DOM).

![Basic To-Do App to Demonstrate How to Translate velocity Into a translate Value With React Spring](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2020/01/react-spring-confetti-velocity-translate.gif?resize=430%2C235&ssl=1)

It’s looking great so far! We’ve successfully translated velocity into a `translate` value. What’s still missing, though, is constant gravity. In terms of physics, that’s easy to implement, since gravity at time `t` is just `t * total time`.

```jsx
const initialY = 0;
  let totalUpwards = 0;
  const startTime = new Date().getTime() / 1000;
  let lastTime = startTime;
  const gravityPerSecond = 30;
  return (
    <AnimatedConfettiDot
      style={{
        transform: upwards.interpolate(upwardsValue => {
          const currentTime = new Date().getTime() / 1000;
          const duration = currentTime - lastTime;
          const verticalTraveled = upwardsValue * duration;
          const totalDuration = currentTime - startTime;
          totalUpwards += verticalTraveled;
          lastTime = currentTime;
          const totalGravity = gravityPerSecond * totalDuration;
          const finalY = initialY - totalUpwards + totalGravity;
          return `translate3d(0, ${finalY}px, 0)`;
        })
      }}
    >
      <circle cx="5" cy="5" r="5" fill="blue" />
    </AnimatedConfettiDot>
  );
};
```

Changing the initial upward velocity to 300 results in the following.

![Basic To-Do App to Demonstrate How to Change Upward Velocity With React Spring](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2020/01/react-spring-confetti-upward-velocity-300.gif?resize=430%2C245&ssl=1)

Let’s add horizontal movement as well. It’s a similar mechanism, so I’ll cut to the chase.

```jsx
const { horizontal, upwards } = useSpring({
    config: config.default,
    from: {
      horizontal: 200,
      upwards: 300
    },
    to: {
      horizontal: 0,
      upwards: 0
    }
  });
  const initialX = 0;
  const initialY = 0;
  let totalUpwards = 0;
  let totalHorizontal = 0;
  const startTime = new Date().getTime() / 1000;
  let lastTime = startTime;
  const gravityPerSecond = 30;
  return (
    <AnimatedConfettiDot
      style={{
        transform: interpolate([upwards, horizontal], (v, h) => {
          const currentTime = new Date().getTime() / 1000;
          const duration = currentTime - lastTime;
          const totalDuration = currentTime - startTime;
          const verticalTraveled = v * duration;
          const horizontalTraveled = h * duration;
          totalUpwards += verticalTraveled;
          totalHorizontal += horizontalTraveled;
          lastTime = currentTime;
          const totalGravity = gravityPerSecond * totalDuration;
          const finalX = initialX + totalHorizontal;
          const finalY = initialY - totalUpwards + totalGravity;
          return `translate3d(${finalX}px, ${finalY}px, 0)`;
        })
      }}
    >
      <circle cx="5" cy="5" r="5" fill="blue" />
    </AnimatedConfettiDot>
  );
```

Similar to the upward velocity, we’ve added a horizontal velocity spring in existing `from` and `to` values and calculated the horizontal distance traveled for each tick of the spring.

The one new thing is that we’re not just interpolating one value anymore, so we need to use the `interpolate` function exported from `react-spring`. This function’s first argument is an array of springs, and the second argument is a function that does something with each of the spring values in that array. So in this particular example, the first argument is a list of the upward and horizontal velocity, and the second argument is a function that has upward velocity as its first argument and horizontal velocity as its second argument.

![Basic To-Do App to Demonstrate How to Interpolate Multiple Values With React Spring](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2020/01/react-spring-confetti-interpolate-multiple-values.gif?resize=430%2C245&ssl=1)

## 4. Anchoring

Before we start making many pieces of confetti go flying, let’s make this single piece actually look like it’s coming out of a specific element.

The first step is to make the confetti appear when the checkbox is clicked.

```jsx
const ToDo = ({ text }) => {
  const [done, setDone] = useState(false);
  return (
    <StyledToDo>
      <input type="checkbox" onChange={() => setDone(!done)} />
      <span>
        {text} {done ? ":ok_hand:" : ""}
      </span>
      {done && <ConfettiDot />}
    </StyledToDo>
  );
};
```

In each `ToDo` component, when the `done` state is true, render a `ConfettiDot`.

![Basic To-Do App to Demonstrate Anchoring With React Spring](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2020/01/react-spring-confetti-anchoring.gif?resize=430%2C245&ssl=1)

It looks like it’s aligned with the checkbox, but if you look closely, you might notice that the animation starts at the top-left of the checkbox. It looks okay, but if it were a different element, such as a text box input, this would look pretty strange.

We’ll use `ref`s to align the animation with the checkbox.

```jsx
const alignWithAnchor = anchorRef => {
  if (anchorRef.current == null) {
    return {
      initialX: 0,
      initialY: 0
    };
  }
  const { height, width } = anchorRef.current.getBoundingClientRect();
  return {
    initialX: width / 2,
    initialY: height / 2
  };
};

const Dot = ({ anchorRef }) => {
  const { initialX, initialY } = alignWithAnchor(anchorRef);
  // ...
}

const ToDo = ({ text }) => {
  const confettiAnchorRef = useRef();
  const [done, setDone] = useState(false);
  return (
    <StyledToDo>
      <input
        ref={confettiAnchorRef}
        type="checkbox"
        onChange={() => setDone(!done)}
      />
      <span>
        {text} {done ? ":ok_hand:" : ""}
      </span>
      {done && <ConfettiDot anchorRef={confettiAnchorRef} />}
    </StyledToDo>
  );
};
```

To use the `ref`, follow these steps:

1. In `ToDo`, call `useRef()`
2. Attach the resulting `ref` to the `input` by using `ref={confettiAnchorRef}` (now the ref will contain the DOM element of the `input`)
3. Pass the ref to `ConfettiDot`
4. In `ConfettiDot`, access the `ref` and pass it to a helper
5. In the helper, calculate the middle of the `ref` element

Now the animation is a little cleaned up.

![Basic To-Do App to Demonstrate How to Build a Confetti Cannon React Spring](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2020/01/react-spring-confetti-cleaned-up-animation.gif?resize=430%2C245&ssl=1)

## 5. Making the cannon

Now that we’ve got a single confetti dot moving the way we want it to when we want it to, let’s make it a confetti cannon that sprays a randomized fan of confetti. We want our confetti cannon component to:

- Have an anchor `ref` prop for alignment
- Have a vertical range
- Have a horizontal range
- Fire a certain number of confetti dots

```jsx
const ToDo = ({ text }) => {
const confettiAnchorRef = useRef();
const [done, setDone] = useState(false);
return (
// ...
{done && }
);
};const ConfettiCannon = ({ anchorRef, dotCount }) => (
<>
{new Array(dotCount).fill().map((_, index) => ())}
</>
);
```

![Basic To-Do App to Demonstrate How to Build a Confetti Cannon React Spring](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2020/01/react-spring-confetti-cannon.gif?resize=430%2C245&ssl=1)

It doesn’t look too different, does it? Even though we’re rendering five confetti dots, they all have identical animations, since the confetti dots have their upward and horizontal movement props baked in. Let’s extract those and randomize them within a range.

```jsx
const randomInRange = (min, max) => {
  return Math.random() * (max - min) + min;
};

const ConfettiCannon = ({ anchorRef, dotCount }) => (
  <>
    {new Array(dotCount).fill().map((_, index) => (
      <ConfettiDot
        key={index}
        anchorRef={anchorRef}
        initialHorizontal={randomInRange(-250, 250)}
        initialUpwards={randomInRange(200, 700)}
      />
    ))}
  </>
);

const Dot = ({ anchorRef, initialHorizontal, initialUpwards }) => {
  const { initialX, initialY } = alignWithAnchor(anchorRef);
  const { horizontal, upwards } = useSpring({
    config: config.default,
    from: {
      horizontal: initialHorizontal,
      upwards: initialUpwards
    },
    to: {
      horizontal: 0,
      upwards: 0
    }
  });

  // ...
}
```

Now instead of having a baked-in initial horizontal and upward velocity, we’ll randomize each dot. Horizontal velocity goes from -250 to 250 to represent dots flying both left of the anchor and right of the anchor, and the upward velocity goes from 200 to 700. Feel free to play around with these values.

![Basic To-Do App to Demonstrate How to Randomize the Dots in a Confetti Cannon Built With React Spring](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2020/01/react-spring-confetti-randomize-dots.gif?resize=430%2C245&ssl=1)

## 6. Polish

At this point, we’ve done all the hard work required for this project. To polish it off, we’ll do the following.

1. Fade out the confetti as it falls
2. Randomize colors
3. Randomize shapes
4. Randomize sizes

Let’s break this down step by step.

### Fade out

The confetti should disappear as it nears the end of its animation. To accomplish this, all we need to do is add the following in `ConfettiDot`.

```jsx
const Dot = ({ anchorRef, initialHorizontal, initialUpwards }) => {
  const { initialX, initialY } = alignWithAnchor(anchorRef);
  const { horizontal, opacity, upwards } = useSpring({
    config: config.default,
    from: {
      horizontal: initialHorizontal,
      opacity: 80,
      upwards: initialUpwards
    },
    to: {
      horizontal: 0,
      opacity: 0,
      upwards: 0
    }
  });

// ...

  return (
    <AnimatedConfettiDot
      style={{
        opacity,
        transform: interpolate([upwards, horizontal], (v, h) => {
          // ...
        })
      }}
    >
      <circle cx="5" cy="5" r="5" fill="blue" />
    </AnimatedConfettiDot>
  );
}
```

Since opacity actually returns a number, and that’s what the valid `style` value is, we don’t need to interpolate it. We can drop it right into the `style` attribute of `AnimatedConfettiDot`.

![Basic To-Do App to Demonstrate How to Change the Opacity in a Confetti Cannon Built With React Spring](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2020/01/react-spring-confetti-cannon-opacity.gif?resize=430%2C245&ssl=1)

### Randomize colors

Blue is fine, but of course, more variance is better. Let’s add a `color` prop to `ConfettiDot`, add a `colors` prop to `ConfettiCannon`, and randomly pick colors from there to assign to created `ConfettiDot`s.

```jsx
const Dot = ({ anchorRef, color, initialHorizontal, initialUpwards }) => {
  // ...

  return (
    <AnimatedConfettiDot
      // ...
    >
      <circle cx="5" cy="5" r="5" fill={color} />
    </AnimatedConfettiDot>
  );
}

const randomInRange = (min, max) => {
  return Math.random() * (max - min) + min;
};

const randomIntInRange = (min, max) => Math.floor(randomInRange(min, max));

const ConfettiCannon = ({ anchorRef, colors, dotCount }) => (
  <>
    {new Array(dotCount).fill().map((_, index) => (
      <ConfettiDot
        key={index}
        anchorRef={anchorRef}
        color={colors[randomIntInRange(0, colors.length)]}
        initialHorizontal={randomInRange(-250, 250)}
        initialUpwards={randomInRange(200, 700)}
      />
    ))}
  </>
);
```

![Basic To-Do App to Demonstrate How to Randomize the Colors of the Dots in a Confetti Cannon Built With React Spring](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2020/01/react-spring-confetti-cannon-randomize-colors.gif?resize=430%2C245&ssl=1)

This can be especially useful if you want to stylize your confetti in the brand colors of the app using this library.

### Randomize shapes

Circles are also fine, but they don’t look like the most convincing confetti pieces in the world. Let’s randomly make squares and triangles as well.

```jsx
const Circle = ({ color, size }) => (
  <circle
    cx={`${size / 2}`}
    cy={`${size / 2}`}
    r={`${(size / 2) * 0.6}`}
    fill={color}
  />
);
const Triangle = ({ color, size }) => {
  const flipped = flipCoin();
  return (
    <polygon
      points={`${size / 2},0 ${size},${randomInRange(
        flipped ? size / 2 : 0,
        size
      )} 0,${randomInRange(flipped ? 0 : size / 2, size)}`}
      fill={color}
    />
  );
};
const Square = ({ color, size }) => {
  const flipped = flipCoin();
  return (
    <rect
      height={`${randomInRange(0, flipped ? size : size / 2)}`}
      width={`${randomInRange(0, flipped ? size / 2 : size)}`}
      fill={color}
    />
  );
};
const getRandomShape = color => {
  const Shape = randomFromArray([Circle, Square, Triangle]);
  return <Shape color={color} size={10} />;
};

return (
  <AnimatedConfettiDot
    // ...
  >
    {getRandomShape(color)}
  </AnimatedConfettiDot>
);
```

Now we’ll randomly get a triangle, square, or circle. The triangle and square have some extra code in them to make sure you never end up with a square that’s just a line or a triangle that’s just a line. I’ve left out the code for `flipCoin` and `randomFromArray` from this snippet, but it’s in the CodeSandbox.

![Basic To-Do App to Demonstrate How to Randomize the Shapes of the Dots in a Confetti Cannon Built With React Spring](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2020/01/react-spring-confetti-cannon-randomize-shapes.gif?resize=430%2C245&ssl=1)

One last thing that’d be nice to polish: as of now, there’s no rotation, which makes it so that each triangle has a point facing directly up, and each rectangle is either fully vertical or fully horizontal. Let’s fix that.

```jsx
const ConfettiCannon = ({ anchorRef, colors, dotCount }) => (
  <>
    {new Array(dotCount).fill().map((_, index) => (
      <ConfettiDot
        key={index}
        anchorRef={anchorRef}
        color={colors[randomIntInRange(0, colors.length)]}
        initialHorizontal={randomInRange(-250, 250)}
        initialUpwards={randomInRange(200, 700)}
        rotate={randomInRange(0, 360)}
      />
    ))}
  </>
);

const Dot = ({
  anchorRef,
  color,
  initialHorizontal,
  initialUpwards,
  rotate
}) => {
  // ...
  return (
    <AnimatedConfettiDot
      style={{
        opacity,
        transform: interpolate([upwards, horizontal], (v, h) => {
          // ...
          return `translate3d(${finalX}px, ${finalY}px, 0) rotate(${rotate}deg)`;
        })
      }}
    >
      {getRandomShape(color)}
    </AnimatedConfettiDot>
  );
};
```

![Basic To-Do App to Demonstrate How to Randomize Rotation of the Shapes in a Confetti Cannon Built With React Spring](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2020/01/react-spring-confetti-cannon-randomize-shape-rotation.gif?resize=430%2C245&ssl=1)

### Randomize size

The last aspect to randomize is the size of each dot. Currently, all the dots are the same size, and it’s especially obvious with the circles. Let’s use a similar approach as we did for rotation.

```jsx
const getRandomShape = (color, size) => {
  const Shape = randomFromArray([Circle, Square, Triangle]);
  return <Shape color={color} size={size} />;
};

const Dot = ({
  anchorRef,
  color,
  initialHorizontal,
  initialUpwards,
  rotate,
  size
}) => {
  // ...
  return (
    <AnimatedConfettiDot
      // ...
    >
      {getRandomShape(color, size)}
    </AnimatedConfettiDot>
  );
};

const ConfettiCannon = ({ anchorRef, colors, dotCount }) => (
  <>
    {new Array(dotCount).fill().map((_, index) => (
      <ConfettiDot
        key={index}
        anchorRef={anchorRef}
        color={colors[randomIntInRange(0, colors.length)]}
        initialHorizontal={randomInRange(-250, 250)}
        initialUpwards={randomInRange(200, 700)}
        rotate={randomInRange(0, 360)}
        size={randomInRange(8, 12)}
      />
    ))}
  </>
);
```

![Basic To-Do App to Demonstrate How to Randomize the Size of the Shapes in a Confetti Cannon Built With React Spring](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2020/01/react-spring-confetti-cannon-randomize-size.gif?resize=430%2C245&ssl=1)

## Conclusion

Congratulations! You’ve made confetti from scratch using React and React Spring. Now you should be much more familiar with using React Spring’s `useSpring` hook to create powerful and performant animations.

I’ll leave you with these branded confetti cannons!

![Basic To-Do App With Branded Confetti Cannons Built With React Spring](https://i1.wp.com/blog.logrocket.com/wp-content/uploads/2020/01/react-spring-branded-confetti-cannons.gif?resize=430%2C245&ssl=1)

* * * 
## 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.](https://www2.logrocket.com/react-performance-monitoring)

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/eq752g8qhbffxt3hp9t4.png)

[LogRocket](https://www2.logrocket.com/react-performance-monitoring) 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.](https://www2.logrocket.com/react-performance-monitoring)
* * *

The post [How to make a confetti cannon with React Spring](https://blog.logrocket.com/how-to-make-a-confetti-cannon-with-react-spring/) appeared first on [LogRocket Blog](https://blog.logrocket.com).