useDynamicAnimation

useDynamicAnimation is a hook that lets you use style objects dynamically, rather than using static variants.

It has all the same performance benefits of useAnimationState, with a more expressive API.

useDynamicAnimation(initialState?)#

const animation = useDynamicAnimation(() => {
// optional function that returns your initial style
return {
height: 100,
}
})
const onLayout = ({ nativeEvent }) => {
animation.animateTo({
...animation.current,
height: nativeEvent.layout.height,
})
}
// pass the animation to state of any Moti component
return <MotiView state={animation} />

Benefits#

  • High performance
  • Zero re-renders
  • Animations run on the native thread
  • Easy API

Arguments#

Receives one (optional) argument: a pure function which returns the initial state. This is similar to React useState's first argument.

const animation = useDynamicAnimation(() => {
// this is your initial state
return {
height: 100,
}
})

Returns#

current#

Get the current animation state. Unlike useState's return value, this can be safely read and accessed synchronously.

const animation = useDynamicAnimation(() => {
// this is your initial state
return {
height: 100,
}
})
const onPress = () => {
console.log(animation.current) // { height: 100 }
}

animateTo(next)#

A function to animate to your next state. This is a worklet, so you can call it from the native thread.

const animation = useDynamicAnimation(() => {
return {
height: 100,
}
})
const onPress = () => {
animation.animateTo({ height: 200 })
}

You can also pass a function which receives the current style and returns the next state:

const animation = useDynamicAnimation(() => {
return {
height: 100,
width: 100,
}
})
const onPress = () => {
animation.animateTo((current) => ({ ...current, height: 200 }))
// or, you could do this! they're the same
animation.animateTo({
...animation.current,
height: 200,
})
}

Do not destructure#

// 😡 don't do this
const { current, animateTo } = useDynamicAnimation()
// ✅ do this!
const animation = useDynamicAnimation()

Sequences#

Any Moti styles are valid here. For example, if you want a sequence animation, just pass an array.

const animation = useDynamicAnimation(() => {
return {
opacity: 1,
}
})
const onPress = () => {
animation.animateTo({
// sequence
opacity: [1, 0.5, { value: 0, delay: 1000 }],
})
}

Full example: Touchable pulse#

import React from 'react'
import { MotiView, useDynamicAnimation } from 'moti'
import {
TapGestureHandler,
TapGestureHandlerGestureEvent,
} from 'react-native-gesture-handler'
import { useAnimatedGestureHandler } from 'react-native-reanimated'
export default function HoverPulse({
scaleTo = 1.05,
style,
children,
...props
}) {
const animation = useDynamicAnimation(() => ({
// this is the initial state
scale: 1,
}))
const onGestureEvent = useAnimatedGestureHandler<TapGestureHandlerGestureEvent>(
{
onStart: () => {
animation.animateTo({ scale: scaleTo })
},
onFinish: () => {
animation.animateTo({ scale: 1 })
},
}
)
return (
<TapGestureHandler onGestureEvent={onGestureEvent}>
<MotiView style={style} state={animation}>
{children}
</MotiView>
</TapGestureHandler>
)
}