Introducing Reanimated 2

Krzysztof Magiera
Software Mansion
Published in
9 min readMay 28, 2020

--

Today we are excited to announce the alpha release of Reanimated 2. With this next major version we, together with Shopify, are bringing to you an entirely new experience of writing performant animations in your React Native app addressing some of the biggest limitations of Reanimated 1.x.

Software Mansion has been involved in work on React Native open source projects for over four years. A few months ago we were contacted by Shopify with an idea of working together on improving the React Native ecosystem. We figured that animations and gesture-based interaction is an area where we can have the biggest impact. As we weren’t satisfied with the state of the art solutions in this space (including the libraries that we created and maintain at Software Mansion), we concluded that to make real progress we had to take a radically different approach when designing the library. Instead of thinking how to overcome the limitations of the React Native framework, we decided to think of how we envision the ideal way of building interactive interfaces. We believe that the next version of Reanimated is as close to that vision as you can get, and are very excited to share it with the rest of the community.

Reanimated 2.0 introduces a set of completely new APIs. Before we go into details on that, we wanted to assure you that version 2 will be backward compatible with Reanimated 1.x to allow for incremental adoption (you will be able to use the same old API and libraries that depend on it as well as adapt new API in other places of your app). We will continue to work on critical fixes to the Reanimated 1.x core and publish such updates both as part of 1.x and 2.x releases.

We had to make Reanimated different to make it better

Reanimated library enables you to create animations and interactions that run on UI thread for improved performance and interactiveness of your app. To build those with Reanimated 1.0 you need to adapt to a totally new mindset of writing animations in a declarative way. We never designed the old declarative API to work that way, instead it was just a reflection of how the library functioned underneath. Because of the declarative approach Reanimated 1.0 is able to serialize interaction as described in JavaScript and recreate it in native Android or iOS. Then, it can use that recreated structure to execute animations on the native code side. Over the past two years, we received a lot of feedback on how difficult this way of defining interaction has been for many of you. While there were many different factors, this feedback has been the primary reason why we decided to completely shift this approach.

From the developer’s standpoint, learning new DSL to work on regular tasks is never a preference (building interactive interfaces is a bread and butter for mobile app engineers). Developers want to use things that are already familiar with, and that follow patterns that they understand. Therefore, we wanted for the next Reanimated to allow for building animations and interactions using just JavaScript. However, to achieve smooth and responsive animations, we still needed the ability to execute them synchronously on the UI thread (this has always been an ultimate promise of Reanimated). Taking inspiration from the Web animation worklets API, we adapt the idea of small JS programs that you can execute on the UI thread. With strong support from Shopify, for the past four months we iterated on many different designs for the React Native worklets API with a goal of making it robust in terms of abilities and seamless to use from the developer’s perspective.

Introducing: Reanimated worklets

The ultimate goal of worklets was for them to define small pieces of JavaScript code that we run when updating view properties or reacting to events on the UI thread. A natural construct in JavaScript for such a purpose was a simple method. With Reanimated 2.x we spawn a secondary JS context on the UI thread that then is able to run JavaScript functions. The only thing that is needed is for that function to have 'worklet' directive at the top:

Functions are a great construct for our needs because you can communicate with the code they run by passing arguments. Each worklet function can be run either on the main React Native thread if you just call that function in your code, or you can execute it on the UI thread using runOnUI. Note that UI execution is asynchronous from the caller’s perspective. When you pass arguments, they will be copied to the UI JS context.

In addition to arguments, functions also capture the context where they are defined. So when you have a variable that is defined outside of the worklet scope but is used inside a worklet, it will also be copied along with the arguments and you’d be able to use it (we refer to it as capturing given params):

Worklets can capture (or take as arguments) from other worklets, in which case when called, they will execute synchronously on the UI thread:

And hey — this works for regular methods too. In fact, console.log is not defined in the UI JS context, but is a reference to a method that the React Native JS context provides. So when we used console.log in the previous examples it was actually executed on the React Native thread.

We make the experience of writing worklets as seamless as possible to make up for all the frustration caused by the difficulties of writing Reanimated 1 code. But we are not done yet with the changes. Worklets are the backbone of new Reanimated, in order to use them with views or events, you need to learn the new worklet-based Reanimated API.

Worklet-based Reanimated API

To keep this post short, we won’t be diving into all the details. Along with the new version of Reanimated, we are launching refreshed documentation where all the aspects of the new API are covered. We wanted, however, to drop a few high-level ideas on how animations and interactions can be defined using the new Reanimated.

To make the association between View attributes and code that can be executed in worklets we are introducing a hook called useAnimatedStyle. When using this hook, you pass a worklet as an argument (you can omit the “worklet” directive as we automatically detect the provided method as a worklet). This worklet is executed whenever we know we need to update the view’s style.

The returned object can be passed to Animated.View as a style:

To make the style hook reactive, we are introducing a concept of shared values. Shared values are similar to Animated.Values in a sense that they have three key roles: to carry data, provide reactiveness and to drive animations. With shared value, the data can be read from and written to using `value` property. Reactiveness is achieved by subscribing to the value property updates. When a shared value is captured by an animated style worklet, the worklet will automatically subscribe to updates, and the style worklet will re-run upon the value change:

In the code below, we update the shared value to some random number when the user presses the button. As a result, the style is updated in the UI thread:

Since worklets are just JavaScript code, we can make the update logic as complex as necessary. You can think of useAnimatedStyle worklet like it was a render function in a React component, just returning a style object instead of JSX. To illustrate that you may think of a case where different styles will be used depending on some variable:

At last some animations

Of course, animations are first-class citizens in Reanimated, so our goal when designing the API was to make animations available at your fingertips. Ideally, it shouldn’t be way more difficult to animate a style update we are making. Let’s take a look:

In the previous section we learned how to make immediate updates of a style property. With new Reanimated, making those changes animate using spring is a matter of wrapping the target value in withSpring helper:

Using this technique, all the updates made to the View’s width are going to be animated. Moreover, the animation is interruptible, which means that when you update the target value before the spring settles, it will start from the position at the given moment (to observe this, we need to press the button much faster):

Check our new documentation website for more examples on animations, and to learn about new ways for event handling.

What’s next?

Reanimated 2 is an alpha release. We wanted to make it available as soon as we could to collect feedback from the community, and haven’t yet had time to smooth some rough edges of the framework. As the implementation relies on the Turbo Modules interface, the setup steps are a bit more complex than simply installing a React Native dependency. Also, because of the above, we currently only support React Native 0.62+. We tried to document all the known limitations and ask for your patience as we work on the known problems. Building Reanimated 2 has consumed a lot of time and we can’t simply discuss all the details in a single blog post. We will be sharing more content as we go, in a form of blog posts and also in a form of webinar that we plan on hosting on Jun 18th. On the webinar, we will be showing a lot more examples and usage patterns, as well as discuss the new architecture and internals of the library.

Reanimated 2 is brought to you by Software Mansion and Shopify with a number of people involved on both ends, and many more friends from the community who helped with testing and early feedback. We can’t even list everyone, but wanted to thank Szymon Kapala and Karol Bisztyga for driving the implementation efforts. Special thanks to the team at Shopify for their support and trust. This release wouldn’t be possible without the remaining part of the open source team at Software Mansion: Kuba Gonet, Wojtek Lewicki, Adrian Klekotko, Kuba Adamczyk and Tomek Zawada were heads down in the last few weeks helping us get the alpha version out. Finally, I wanted to thank our feedback group and early testers from Expo, Shopify and many individuals from the react-native community who helped us a ton in shaping the API and getting a number of bugs fixed (special thanks to Terry Sahaidak for his involvement in this process).

--

--

Director of engineering at Software Mansion. React Native contributor and former member of React Native team at Facebook.