Imperative API

The imperative API enables you to update your animations without requiring a react-render to occur. This is useful for animations that are not tied to a component's lifecycle, such as animations that are triggered by user input.

In essence, it is simply a SpringRef with the hook's Controller attached to it. You can additionally add more Controllers to the SpringRef to create a multi-controller animation, similar to that of the useChain hook.

Comparison

What we can see from the below comparions, is that using the api object either returned from your useSpring hook, or generated via useSpringRef and passed to the hook, means your components do not re-render when the animation runs.

import { useState } from 'react'
import { useSpring, useSpringRef, animated } from '@react-spring/web'
const ApiComponent = () => {
const api = useSpringRef()
const springs = useSpring({
ref: api,
from: { x: 0 },
})
const handleClick = () => {
api.start({
to: {
x: springs.x.get() === 100 ? 0 : 100,
},
})
}
return (
<div className="flex-container">
<animated.div onClick={handleClick} style={{ width: 80, height: 80, background: '#ff6d6d', borderRadius: 8, ...springs, }} />
<span>Render ID – {Math.random()}</span>
</div>
)
}
const StateComponent = () => {
const [forward, setForward] = useState(false)
const springs = useSpring({
x: forward ? 100 : 0,
})
const handleClick = () => {
setForward(s => !s)
}
return (
<div className="flex-container">
<animated.div onClick={handleClick} style={{ width: 80, height: 80, background: '#ff6d6d', borderRadius: 8, ...springs, }} />
<span>Render ID – {Math.random()}</span>
</div>
)
}
export default function MyComponent() {
return (
<div className="flex-container--column">
<ApiComponent />
<StateComponent />
</div>
)
}

This way of working with react-spring lets you handle updates quicker and more effectively such as the position of the user's mouse. It is the recommended approach for working with this library.

When using a SpringRef or api return from a hook, any updates to the hook's configuration object are treated as updates and therefore will not trigger the animation to run. You must call .start() to trigger the animation, thus flushing the update queue.

Methods

The entire list of methods & properties are visible here. It's API signature is similar to both the Controller and SpringValue class methods. This is done to create a single unified language across the library.

The most important methods you'll most likely use are start and set. However, if you are opting to use the Controller class manually as opposed to using our hooks/components, then you would have to manually handle the lifecycle of adding/removing Controllers.

Upgrading from v8

If you're upgrading from v8 of react-spring, then welcome! The imperative API is a new feature that has been added to v9. You're probably more used to an api signature like this:

const [styles, set, stop] = useSpring(() => ({ x: 0 }))
set({
x: 1,
})

This was okay for at the time, but as Controllers have become more powerful, it became clear that we needed a way a more scalable way to add methods to the signature without extending the array too far.

The new api signature is like this:

const [styles, api] = useSpring(() => ({ x: 0 }))
api.start({
x: 1,
})

We've used start in the above example demonstrating migration, this is because set acts like:

api.start({
x: 1,
immediate: true,
})