react-native-reanimated 4.2.2 → 4.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -99,7 +99,8 @@ class ReanimatedModuleProxy : public ReanimatedModuleProxySpec,
99
99
  void maybeRunCSSLoop();
100
100
  double getCssTimestamp();
101
101
 
102
- void performOperations(const bool isTriggeredByEvent);
102
+ void performOperations();
103
+ void performNonLayoutOperations();
103
104
 
104
105
  void setViewStyle(jsi::Runtime &rt, const jsi::Value &viewTag, const jsi::Value &viewStyle) override;
105
106
 
@@ -179,6 +180,7 @@ class ReanimatedModuleProxy : public ReanimatedModuleProxySpec,
179
180
 
180
181
  private:
181
182
  void commitUpdates(jsi::Runtime &rt, const UpdatesBatch &updatesBatch);
183
+ void applySynchronousUpdates(UpdatesBatch &updatesBatch, bool allowPartialUpdates = false);
182
184
 
183
185
  const bool isReducedMotion_;
184
186
  bool shouldFlushRegistry_ = false;
@@ -112,8 +112,12 @@ bool NativeProxy::isAnyHandlerWaitingForEvent(const std::string &eventName, cons
112
112
  return reanimatedModuleProxy_->isAnyHandlerWaitingForEvent(eventName, emitterReactTag);
113
113
  }
114
114
 
115
- void NativeProxy::performOperations(const bool isTriggeredByEvent) {
116
- reanimatedModuleProxy_->performOperations(isTriggeredByEvent);
115
+ void NativeProxy::performOperations() {
116
+ reanimatedModuleProxy_->performOperations();
117
+ }
118
+
119
+ void NativeProxy::performNonLayoutOperations() {
120
+ reanimatedModuleProxy_->performNonLayoutOperations();
117
121
  }
118
122
 
119
123
  bool NativeProxy::getIsReducedMotion() {
@@ -127,6 +131,7 @@ void NativeProxy::registerNatives() {
127
131
  makeNativeMethod("installJSIBindings", NativeProxy::installJSIBindings),
128
132
  makeNativeMethod("isAnyHandlerWaitingForEvent", NativeProxy::isAnyHandlerWaitingForEvent),
129
133
  makeNativeMethod("performOperations", NativeProxy::performOperations),
134
+ makeNativeMethod("performNonLayoutOperations", NativeProxy::performNonLayoutOperations),
130
135
  makeNativeMethod("invalidateCpp", NativeProxy::invalidateCpp)});
131
136
  }
132
137
 
@@ -55,7 +55,8 @@ class NativeProxy : public jni::HybridClass<NativeProxy>, std::enable_shared_fro
55
55
 
56
56
  double getAnimationTimestamp();
57
57
  bool isAnyHandlerWaitingForEvent(const std::string &eventName, const int emitterReactTag);
58
- void performOperations(const bool isTriggeredByEvent);
58
+ void performOperations();
59
+ void performNonLayoutOperations();
59
60
  bool getIsReducedMotion();
60
61
  void requestRender(std::function<void(double)> onRender);
61
62
  void registerEventHandler();
@@ -0,0 +1,82 @@
1
+ package com.swmansion.reanimated;
2
+
3
+ import android.app.Activity;
4
+ import android.os.Handler;
5
+ import android.os.Looper;
6
+ import android.view.View;
7
+ import android.view.ViewTreeObserver;
8
+ import com.facebook.react.bridge.ReactApplicationContext;
9
+ import com.facebook.react.bridge.UiThreadUtil;
10
+ import javax.annotation.Nullable;
11
+
12
+ /** Tracks whether the current UI thread turn is inside a draw pass. */
13
+ class DrawPassDetector {
14
+ private final ReactApplicationContext mContext;
15
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
16
+ private final Runnable mClearRunnable = () -> mIsInDrawPass = false;
17
+ private boolean mIsInDrawPass = false;
18
+ @Nullable private View mDecorView = null;
19
+
20
+ private final ViewTreeObserver.OnDrawListener mOnDrawListener =
21
+ () -> {
22
+ mIsInDrawPass = true;
23
+ mHandler.postAtFrontOfQueue(mClearRunnable);
24
+ };
25
+
26
+ DrawPassDetector(ReactApplicationContext context) {
27
+ mContext = context;
28
+ }
29
+
30
+ void initialize() {
31
+ Activity activity = mContext.getCurrentActivity();
32
+ if (activity == null) {
33
+ return;
34
+ }
35
+
36
+ View decorView = activity.getWindow().getDecorView();
37
+ if (decorView == mDecorView) {
38
+ return;
39
+ }
40
+
41
+ // Decor view has changed (e.g. Activity recreated) — detach from the old one first.
42
+ if (mDecorView != null) {
43
+ ViewTreeObserver oldObserver = mDecorView.getViewTreeObserver();
44
+ if (oldObserver.isAlive()) {
45
+ oldObserver.removeOnDrawListener(mOnDrawListener);
46
+ }
47
+ mDecorView = null;
48
+ }
49
+
50
+ ViewTreeObserver observer = decorView.getViewTreeObserver();
51
+ if (!observer.isAlive()) {
52
+ return;
53
+ }
54
+
55
+ mDecorView = decorView;
56
+ observer.addOnDrawListener(mOnDrawListener);
57
+ }
58
+
59
+ boolean isInDrawPass() {
60
+ return mIsInDrawPass;
61
+ }
62
+
63
+ void invalidate() {
64
+ if (UiThreadUtil.isOnUiThread()) {
65
+ invalidateOnUiThread();
66
+ } else {
67
+ mHandler.post(this::invalidateOnUiThread);
68
+ }
69
+ }
70
+
71
+ private void invalidateOnUiThread() {
72
+ if (mDecorView != null) {
73
+ ViewTreeObserver observer = mDecorView.getViewTreeObserver();
74
+ if (observer.isAlive()) {
75
+ observer.removeOnDrawListener(mOnDrawListener);
76
+ }
77
+ mDecorView = null;
78
+ }
79
+ mHandler.removeCallbacks(mClearRunnable);
80
+ mIsInDrawPass = false;
81
+ }
82
+ }
@@ -110,7 +110,9 @@ public class NativeProxy {
110
110
 
111
111
  public native boolean isAnyHandlerWaitingForEvent(String eventName, int emitterReactTag);
112
112
 
113
- public native void performOperations(boolean isTriggeredByEvent);
113
+ public native void performOperations();
114
+
115
+ public native void performNonLayoutOperations();
114
116
 
115
117
  protected native void installJSIBindings();
116
118
 
@@ -503,7 +505,7 @@ public class NativeProxy {
503
505
  void maybeFlushUIUpdatesQueue() {
504
506
  UiThreadUtil.assertOnUiThread();
505
507
  if (!mNodesManager.isAnimationRunning()) {
506
- mNodesManager.performOperations(false);
508
+ mNodesManager.performOperationsRespectingDrawPass();
507
509
  }
508
510
  }
509
511
  }
@@ -44,6 +44,7 @@ public class NodesManager implements EventDispatcherListener {
44
44
  private ConcurrentLinkedQueue<CopiedEvent> mEventQueue = new ConcurrentLinkedQueue<>();
45
45
  private double lastFrameTimeMs;
46
46
  private FabricUIManager mFabricUIManager;
47
+ private final DrawPassDetector mDrawPassDetector;
47
48
 
48
49
  public NativeProxy getNativeProxy() {
49
50
  return mNativeProxy;
@@ -57,6 +58,8 @@ public class NodesManager implements EventDispatcherListener {
57
58
  mNativeProxy = null;
58
59
  }
59
60
 
61
+ mDrawPassDetector.invalidate();
62
+
60
63
  if (mFabricUIManager != null) {
61
64
  mFabricUIManager.getEventDispatcher().removeListener(this);
62
65
  }
@@ -69,6 +72,7 @@ public class NodesManager implements EventDispatcherListener {
69
72
  assert uiManager != null;
70
73
  mCustomEventNamesResolver = uiManager::resolveCustomDirectEventName;
71
74
  mEventEmitter = context.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class);
75
+ mDrawPassDetector = new DrawPassDetector(context);
72
76
 
73
77
  mReactChoreographer = ReactChoreographer.getInstance();
74
78
  mChoreographerCallback =
@@ -115,11 +119,33 @@ public class NodesManager implements EventDispatcherListener {
115
119
  }
116
120
  }
117
121
 
118
- public void performOperations(boolean isTriggeredByEvent) {
122
+ public void performOperations() {
119
123
  UiThreadUtil.assertOnUiThread();
120
124
  if (mNativeProxy != null) {
121
- mNativeProxy.performOperations(isTriggeredByEvent);
125
+ mNativeProxy.performOperations();
126
+ }
127
+ }
128
+
129
+ void performNonLayoutOperations() {
130
+ UiThreadUtil.assertOnUiThread();
131
+ if (mNativeProxy != null) {
132
+ mNativeProxy.performNonLayoutOperations();
133
+ }
134
+ }
135
+
136
+ void performOperationsRespectingDrawPass() {
137
+ mDrawPassDetector.initialize();
138
+ if (isInDrawPass()) {
139
+ performNonLayoutOperations();
140
+ startUpdatingOnAnimationFrame();
141
+ return;
122
142
  }
143
+
144
+ performOperations();
145
+ }
146
+
147
+ boolean isInDrawPass() {
148
+ return mDrawPassDetector.isInDrawPass();
123
149
  }
124
150
 
125
151
  private void onAnimationFrame(long frameTimeNanos) {
@@ -130,6 +156,8 @@ public class NodesManager implements EventDispatcherListener {
130
156
  Trace.beginSection("onAnimationFrame");
131
157
  }
132
158
 
159
+ mDrawPassDetector.initialize();
160
+
133
161
  double currentFrameTimeMs = frameTimeNanos / 1000000.;
134
162
  if (mSlowAnimationsEnabled) {
135
163
  currentFrameTimeMs =
@@ -155,7 +183,7 @@ public class NodesManager implements EventDispatcherListener {
155
183
  }
156
184
  }
157
185
 
158
- performOperations(false);
186
+ performOperations();
159
187
  }
160
188
 
161
189
  mCallbackPosted.set(false);
@@ -189,7 +217,7 @@ public class NodesManager implements EventDispatcherListener {
189
217
  // the UI thread.
190
218
  if (UiThreadUtil.isOnUiThread()) {
191
219
  handleEvent(event);
192
- performOperations(true);
220
+ performOperationsRespectingDrawPass();
193
221
  } else {
194
222
  String eventName = mCustomEventNamesResolver.resolveCustomEventName(event.getEventName());
195
223
  int viewTag = event.getViewTag();
@@ -46,7 +46,7 @@ std::shared_ptr<ReanimatedModuleProxy> createReanimatedModuleProxy(
46
46
  std::weak_ptr<ReanimatedModuleProxy> weakReanimatedModuleProxy = reanimatedModuleProxy; // to avoid retain cycle
47
47
  [nodesManager registerPerformOperations:^() {
48
48
  if (auto reanimatedModuleProxy = weakReanimatedModuleProxy.lock()) {
49
- reanimatedModuleProxy->performOperations(false);
49
+ reanimatedModuleProxy->performOperations();
50
50
  }
51
51
  }];
52
52
 
@@ -6,7 +6,7 @@
6
6
  },
7
7
  "4.2.x": {
8
8
  "react-native": ["0.80", "0.81", "0.82", "0.83", "0.84"],
9
- "react-native-worklets": ["0.7.x"]
9
+ "react-native-worklets": ["0.7.x", "0.8.x"]
10
10
  },
11
11
  "4.1.x": {
12
12
  "react-native": ["0.78", "0.79", "0.80", "0.81", "0.82"],
@@ -5,5 +5,5 @@
5
5
  * version used to build the native part of the library in runtime. Remember to
6
6
  * keep this in sync with the version declared in `package.json`
7
7
  */
8
- export const jsVersion = '4.2.2';
8
+ export const jsVersion = '4.2.3';
9
9
  //# sourceMappingURL=jsVersion.js.map
@@ -3,5 +3,5 @@
3
3
  * version used to build the native part of the library in runtime. Remember to
4
4
  * keep this in sync with the version declared in `package.json`
5
5
  */
6
- export declare const jsVersion = "4.2.2";
6
+ export declare const jsVersion = "4.2.3";
7
7
  //# sourceMappingURL=jsVersion.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-reanimated",
3
- "version": "4.2.2",
3
+ "version": "4.2.3",
4
4
  "description": "More powerful alternative to Animated library for React Native.",
5
5
  "keywords": [
6
6
  "react-native",
@@ -37,7 +37,8 @@
37
37
  "build": "yarn workspace react-native-worklets build && bob build",
38
38
  "circular-dependency-check": "yarn madge --extensions js,jsx --circular lib",
39
39
  "prepack": "cp ../../README.md ./README.md",
40
- "postpack": "rm ./README.md"
40
+ "postpack": "rm ./README.md",
41
+ "validate-peers": "node ../../scripts/validate-compatibility-peer-dependencies.js"
41
42
  },
42
43
  "main": "lib/module/index",
43
44
  "module": "lib/module/index",
@@ -92,13 +93,13 @@
92
93
  },
93
94
  "homepage": "https://docs.swmansion.com/react-native-reanimated",
94
95
  "dependencies": {
95
- "react-native-is-edge-to-edge": "1.2.1",
96
- "semver": "7.7.3"
96
+ "react-native-is-edge-to-edge": "^1.2.1",
97
+ "semver": "^7.7.3"
97
98
  },
98
99
  "peerDependencies": {
99
100
  "react": "*",
100
- "react-native": "*",
101
- "react-native-worklets": ">=0.7.0"
101
+ "react-native": "0.80 - 0.84",
102
+ "react-native-worklets": "0.7 - 0.8"
102
103
  },
103
104
  "devDependencies": {
104
105
  "@babel/core": "7.28.4",
@@ -132,7 +133,7 @@
132
133
  "react-native-builder-bob": "0.40.13",
133
134
  "react-native-svg": "15.14.0",
134
135
  "react-native-web": "0.21.1",
135
- "react-native-worklets": "0.8.0-nightly-20260211-96ab3f00d",
136
+ "react-native-worklets": "0.8.0",
136
137
  "react-test-renderer": "19.2.3",
137
138
  "typescript": "5.8.3"
138
139
  },
@@ -1,4 +1 @@
1
- {
2
- "min": "0.7.0",
3
- "max": "0.7"
4
- }
1
+ { "min": "0.7.0", "max": "0.8" }
@@ -4,4 +4,4 @@
4
4
  * version used to build the native part of the library in runtime. Remember to
5
5
  * keep this in sync with the version declared in `package.json`
6
6
  */
7
- export const jsVersion = '4.2.2';
7
+ export const jsVersion = '4.2.3';