Reanimated 2 Rewrites the Rules for React Native Gestures and Animations

Software Mansion’s alpha release of Reanimated 2 marks a fundamental shift in how developers approach gestures and animations in React Native. The new version abandons the declarative domain-specific language (DSL) that defined Reanimated 1 in favor of a concept borrowed from an experimental web API: animation worklets. These are JavaScript functions that run on an isolated UI thread context, independent of the main JavaScript thread. The idea, first floated by Krzysztof Magiera at a React Native Community meetup in Kraków, was backed by Shopify as part of its broader support for Software Mansion’s open-source work.

The core problem Reanimated 2 tackles is keeping complete user interactions on the UI thread, so there’s no need to coordinate with—or wait on—the JavaScript thread to compute animation frames. Reanimated 1 solved this with a declarative DSL that had to be set up in advance. That approach worked but came at a cost: a steep learning curve, a limited instruction set, and overhead at initialization time. Developers had to adopt a declarative mindset, rewriting basic math like coordinate conversions, trigonometry, and bezier curves in the DSL. Some tasks, such as date or number formatting, still forced a crossing of the async React Native bridge. And because animation nodes were declared at startup, performance suffered as more nodes meant more messages exchanged between threads. Memoization—avoiding unnecessary re-declarations—became a substantial source of bugs.

What Are Animation Worklets?

Rather than starting from the constraint of avoiding the bridge, the Software Mansion team inverted the question: what would gesture and animation development look like if there were no constraints at all? The answer is worklets, declared with the worklet directive. These functions run on the UI thread and can receive parameters, access constants from the JavaScript thread, invoke other worklet functions synchronously, and call JavaScript-thread functions asynchronously. They bear some resemblance to web workers or OpenGL shaders—isolated pieces of code executed independently.

Worklets offer six key properties:

  1. They run on the UI thread.
  2. They are declared via the worklet directive.
  3. They can be invoked from the JS thread and receive parameters.
  4. They can invoke other worklet functions synchronously.
  5. They can access constants from the JS thread.
  6. They can asynchronously call functions from the JS thread.

To demonstrate the capability of the new API, Software Mansion provides a liquid-swipe example that combines bezier curve interpolation, gesture handling, and physics-based animations—an indication that Reanimated 2 is suitable for advanced, complex interactions.

The New Hooks-Based API

Writing gestures and animations with Reanimated 2 involves three tasks: creating animation values, handling gesture states, and assigning those values to component properties. The new API provides five hooks to cover these needs.

Creating Animation Values

Two hooks handle value creation. useSharedValue() creates a shared value similar to Animated.Value, but it exists on both the JavaScript and UI threads simultaneously. useDerivedValue() creates a shared value based on the execution of a worklet, allowing derived calculations to live on the UI thread.

Handling Gestures

The useAnimatedGestureHandler() hook connects worklets to any gesture handler from react-native-gesture-handler. Each event callback receives two parameters: event, containing the gesture handler's values, and context, which persists state across gesture events.

Assigning Values to Properties

useAnimatedStyle() returns a style object for assignment to an animated component. For non-style properties, useAnimatedProps() works similarly, with animated props set via the animatedProps property.

A Practical Example: Dragging a View

Consider a card that can be dragged around the screen. As with v1, you create two shared values for translation on the x and y axes and wrap the card in a PanGesture handler. The animation values are created with useSharedValue and assigned to an animated view via useAnimatedStyle. The useAnimatedGestureHandler then handles three phases of the gesture:

  1. On gesture start, store the current translate values in the context object to track cumulative translation.
  2. While the gesture is active, assign the gesture's translation plus the stored offset to translate.
  3. On release, apply a decay animation based on the release velocity so the view moves like a physical object.

The complete example is available in the reanimated-2 directory of the can-it-be-done-in-react-native repository on GitHub.

Looking Ahead

Reanimated 2 significantly lowers the barrier to building complex user interactions in React Native. It eliminates the need to cross the React Native bridge for tasks like value formatting and improves initialization performance, which could have meaningful implications for scenarios such as navigation transitions. The project repository includes many examples showcasing the new API's range. The shift from a declarative DSL to worklets represents not just an incremental update, but a new way of thinking about how gestures and animations are written for the platform.