It depends on how you want to interact with your component, do you want to use the api or simply supply updated props?
// update by regenerating springProps from some other state
const springProps = useSpring(props)
// update springProps with api
const [springProps, api] = useSpring(() => props)
Updating by regenerating the spring
With the first example, using one of the animated native elements (animated.XXX
) you will rerender the animated wrapper every time you want to update the state, because you will pass it a new, updated springProps
object every time you update it, which will cause it to rerender. Or... this is only partially true, the individual SpringValue
's in the returned object will be the same with both methods so if you pass them as individual props, rerendering would theoretically not be necessary but if you pass them as a whole object (when springProps
is a style
object for example) it will be a changed object from last render and cause a rerender of the animated
wrapper.
When you use a custom element that does not take a ref inside the wrapper instead of one of the native elements, the component will rerender once for every animation frame. This is suboptimal from a performance perspective, but with this strategy, you can use whichever api (prop names) you want for your component, much like you have done.
Here is a sandbox with this solution that works: sandbox
You can observe that the animation works but also that the component rerenders a lot.
Updating via the api
If you want to make it more efficient, and use the api for updating your custom component, you need to adhere to a few rules. When you use the api, react-spring
updates the element via a ref on the corresponding DOM element, and therefore, react-spring
must understand how to update the element without requiring React to rerender it. This implies:
- Your custom element must be able to hold a ref
- Your custom element must attach the ref to a DOM element on which you want all animations to take place. Because
forwardRef
doesn't allow you to add multiple refs, changes cannot take place on multiple DOM elements inside your custom component if you want to wrap it in animated
(there are other strategies to solve this, such as NOT wrapping your component in animated
and instead use native animated.XXX
elements inside your component and pass SpringValue
s as props).
- The property names of your custom component must correspond to the properties you want to update on the DOM element to which the ref its attached. Otherwise
react-spring
will not understand how to update this element.
Since your element has a lot of custom properties, react-spring
won't be able to update your component via the api. It will attempt to do so by simply setting the updated properties on the element to which the ref is attached, but since you need React to map the custom properties to the actual properties on the DOM element, this will fail (no DOM element that I know of have the set of properties that you provide).
As an example of how to accomplish this, here is a sandbox showing the outlines of this strategy: sandbox
Here you can see that the component renders only once and can still be updated. You can also see that the properties used on the custom component wrapped in animated
corresponds to props on a div
element, enabling react-spring
to do exactly what we want (the children of the AnimatedHomeContent
is a special prop in React named props.children
which react-spring
knows how to deal with).
<AnimatedHomeContent style={{ backgroundColor: spring.backgroundColor }}>
{spring.content}
</AnimatedHomeContent>
In the sandbox is also a bad example where other property names are used.
<AnimatedHomeContentBad
backgroundColor={spring.backgroundColor}
content={spring.content}
/>
To get a correct behaviour from this version, React has to process the component to map the input props to the native DOM element props. When updating this version via the api, react-spring
does not rerender the component (since it can take a ref) and instead sets the updated properties on the element to which the ref is attached (inspect the element in the console to see for yourself that these props are set after updating). Since the properties are not real properties, nothing updates or animates on the component.