Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<061d668cf04041f4d3d2f48f11dc739f>>
* @generated SignedSource<<5f6861a5aa2d6024ad8d4c236652bf64>>
*/

/**
Expand All @@ -27,7 +27,7 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi

override fun cdpInteractionMetricsEnabled(): Boolean = false

override fun cxxNativeAnimatedEnabled(): Boolean = false
override fun cxxNativeAnimatedEnabled(): Boolean = true

override fun defaultTextToOverflowHidden(): Boolean = true

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<8dfc52502bd539e5e43d547f895a6d33>>
* @generated SignedSource<<d0e19eae3c8e1f69383642a42172bb11>>
*/

/**
Expand Down Expand Up @@ -36,7 +36,7 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider {
}

bool cxxNativeAnimatedEnabled() override {
return false;
return true;
}

bool defaultTextToOverflowHidden() override {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ const definitions: FeatureFlagDefinitions = {
ossReleaseStage: 'none',
},
cxxNativeAnimatedEnabled: {
defaultValue: false,
defaultValue: true,
metadata: {
dateAdded: '2025-03-14',
description:
Expand Down
37 changes: 22 additions & 15 deletions packages/react-native/src/private/animated/NativeAnimatedHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import type {EventSubscription} from '../../../Libraries/vendor/emitter/EventEmi

import NativeAnimatedNonTurboModule from '../../../Libraries/Animated/NativeAnimatedModule';
import NativeAnimatedTurboModule from '../../../Libraries/Animated/NativeAnimatedTurboModule';
import queueMicrotask from '../../../Libraries/Core/Timers/queueMicrotask';
import NativeEventEmitter from '../../../Libraries/EventEmitter/NativeEventEmitter';
import RCTDeviceEventEmitter from '../../../Libraries/EventEmitter/RCTDeviceEventEmitter';
import Platform from '../../../Libraries/Utilities/Platform';
Expand Down Expand Up @@ -57,7 +58,6 @@ const isSingleOpBatching =
Platform.OS === 'android' &&
NativeAnimatedModule?.queueAndExecuteBatchedOperations != null &&
ReactNativeFeatureFlags.animatedShouldUseSingleOp();
let flushQueueImmediate = null;

const eventListenerGetValueCallbacks: {
[number]: (value: number) => void,
Expand All @@ -71,6 +71,20 @@ let globalEventEmitterAnimationFinishedListener: ?EventSubscription = null;
const shouldSignalBatch: boolean =
ReactNativeFeatureFlags.cxxNativeAnimatedEnabled();

let flushQueueGeneration = 1;
function scheduleQueueFlush(): void {
const generation = ++flushQueueGeneration;
queueMicrotask(() => {
if (generation !== flushQueueGeneration) {
return;
}
API.flushQueue();
});
}
function cancelQueueFlush(): void {
flushQueueGeneration++;
}

function createNativeOperations(): NonNullable<typeof NativeAnimatedModule> {
const methodNames = [
'createAnimatedNode', // 1
Expand Down Expand Up @@ -116,8 +130,7 @@ function createNativeOperations(): NonNullable<typeof NativeAnimatedModule> {
// details, see `NativeAnimatedModule.queueAndExecuteBatchedOperations`.
singleOpQueue.push(operationID, ...args);
if (shouldSignalBatch) {
clearImmediate(flushQueueImmediate);
flushQueueImmediate = setImmediate(API.flushQueue);
scheduleQueueFlush();
}
};
}
Expand All @@ -137,8 +150,7 @@ function createNativeOperations(): NonNullable<typeof NativeAnimatedModule> {
} else if (shouldSignalBatch) {
// $FlowExpectedError[incompatible-call] - Dynamism.
queue.push(() => method(...args));
clearImmediate(flushQueueImmediate);
flushQueueImmediate = setImmediate(API.flushQueue);
scheduleQueueFlush();
} else {
// $FlowExpectedError[incompatible-call] - Dynamism.
method(...args);
Expand Down Expand Up @@ -190,9 +202,7 @@ const API = {
invariant(NativeAnimatedModule, 'Native animated module is not available');

if (ReactNativeFeatureFlags.animatedShouldDebounceQueueFlush()) {
const prevImmediate = flushQueueImmediate;
clearImmediate(prevImmediate);
flushQueueImmediate = setImmediate(API.flushQueue);
scheduleQueueFlush();
} else {
API.flushQueue();
}
Expand All @@ -218,7 +228,6 @@ const API = {
NativeAnimatedModule,
'Native animated module is not available',
);
flushQueueImmediate = null;

if (singleOpQueue.length === 0) {
return;
Expand All @@ -239,7 +248,6 @@ const API = {
NativeAnimatedModule,
'Native animated module is not available',
);
flushQueueImmediate = null;

if (queue.length === 0) {
return;
Expand Down Expand Up @@ -299,11 +307,10 @@ const API = {

waitingForQueuedOperations.add(id);
queueOperations = true;
if (
ReactNativeFeatureFlags.animatedShouldDebounceQueueFlush() &&
flushQueueImmediate
) {
clearImmediate(flushQueueImmediate);
// Entering explicit queue mode: drop any flush already scheduled so ops
// accumulate until `disableQueue`.
if (ReactNativeFeatureFlags.animatedShouldDebounceQueueFlush()) {
cancelQueueFlush();
}
},
startAnimatingNode: (isSingleOpBatching
Expand Down
Loading
Loading