Hooks in react-spring, a tutorial

Goo in 20 lines or less, using React-futures hooks feature

Yesterday the React-team finally unveiled their vision of a class-less future in React. Today we’re going to take a look at how to use this for animations, using react-spring 6.0.

The full implementation of useSpring

First of all, you would think of react-spring as being render-props driven. Render props are expressive, explicit, and usually very easy to use. But since it is internally steered imperatively, supporting hooks was just a matter of a couple of lines added to its core. The export is now live under react-spring@6.1.0. If you want to use hooks, you will need react and react-dom alpha, otherwise it won’t run. Both apis, the imperative one and hooks, are explained in full detail here.

Basically useSpring turns any data into animated data, with a single line. Throw in whatever you want, numbers, colors, percentages, anything really, just drop it in and place the output into your view. Like so:

So let’s make some cool looking goo with this, whatever the purpose …

Fetching hooks

Let’s start by importing a few essentials. We’re going to use React of course, and since we plan using side-effects (mouse-events) we fetch useEffect while we’re at it. useSpring is the hook we’re going to animate with.

Forming a trail

Next we’re going to create a pure function, this is critical, you can only use hooks in functions, and they need to be declared in top-function scope.

useSpring creates a persistent hook that takes raw values and returns animated values, which are later bound to a view. You can update your spring by overwriting the hook, it will remember previous values and animate adaptively. Additionally useSpring returns an updater, similar to useState, with the distinction that the set function will not cause the component to render, which is useful in situations where you are dealing with event input. We want the spring to update, and the view to animate, without refreshing the component on every mouse-move.

One goo-drop follows the mouse, while the others should trail, we do this by referencing the animated values so that one spring naturally follows the output of another.

Finally we define a basic function that takes [x, y] and forms a css-transform-statement, we need this for interpolation later on. A little trick that i learned once, you can stack transforms, so we shift blobs to mouse-coordinates first, then shift them half their size back so that they are cursor-centric.

Handling the mouse

useEffect is Reacts way of creating a side-effect. We would like to register an event-handler on mount and unregister it on unmount, additionally we need to listen for mouse-movements in order to update our spring, this is where the set function mentioned above comes into play. Notice how we only need to update the first spring, since the others will follow naturally (with slightly slower spring configs).

The [] in the end of useEffect prevents React from running it every update, think of it ascomponentDidMount and componentWillUnmount combined into one effect.

Creating an SVG filter

This step is straight forward, we drop an SVG with a gaussian blur and a color matrix into the scene. Everything is explained here in detail. In synthesis, all we do is animate a couple of shapes while the SVG filter will later do its thing and make it appear as if they would merge together.

A small warning while we’re at it, sadly some browsers still struggle with filters or can’t process them on the GPU (which can make it very slow). I wouldn’t exactly recommend putting this on your website.

Rendering out the animated blobs

This is the last step and we’re already done. Here we simply define a couple of divs and animate their transforms. We are extending the divs fromanimated which allows react-springs to animate outside of react. We take the transform that we defined earlier, apply it, and this is it. Wasn’t so hard, was it?

Et voilà, and this is how it looks …

Hope it was fun!

My name is Paul Henschel, i am based in St. Gallen, Switzerland. I am the founder of Luxundlaune, a photography platform in Germany, Paranoidandroid, a custom rom for Android and several minor open source projects.

You can reach me on Twitter and on Github.