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>
  )
}