Skip to content

Commit ce75271

Browse files
zeyapfacebook-github-bot
authored andcommitted
Gate logic to remove js sync at end of native animation loop (#52068)
Summary: Pull Request resolved: #52068 ## Changelog: [Internal] [Changed] - Gate logic to remove js sync at end of native animation loop because #51264 is causing regression in some cases, and was recently reverted again in #51933 . Using an extra feature flag to gate this potential optimization Reviewed By: lenaic Differential Revision: D76759441 fbshipit-source-id: 6950ab746b02af6e0b710ded0ddb6993673e5212
1 parent 99c60bf commit ce75271

4 files changed

Lines changed: 46 additions & 17 deletions

File tree

packages/react-native/Libraries/Animated/__tests__/Animated-itest.js

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7+
* @fantom_flags cxxNativeAnimatedRemoveJsSync:*
78
* @flow strict-local
89
* @format
910
*/
@@ -16,6 +17,7 @@ import ensureInstance from '../../../src/private/__tests__/utilities/ensureInsta
1617
import * as Fantom from '@react-native/fantom';
1718
import {createRef} from 'react';
1819
import {Animated, View, useAnimatedValue} from 'react-native';
20+
import * as ReactNativeFeatureFlags from 'react-native/src/private/featureflags/ReactNativeFeatureFlags';
1921
import ReactNativeElement from 'react-native/src/private/webapis/dom/nodes/ReactNativeElement';
2022

2123
test('moving box by 100 points', () => {
@@ -73,11 +75,15 @@ test('moving box by 100 points', () => {
7375
Fantom.unstable_produceFramesForDuration(500);
7476

7577
// Animation is completed now. C++ Animated will commit the final position to the shadow tree.
76-
expect(viewElement.getBoundingClientRect().x).toBe(100);
78+
if (ReactNativeFeatureFlags.cxxNativeAnimatedRemoveJsSync()) {
79+
expect(viewElement.getBoundingClientRect().x).toBe(100);
80+
// TODO(T223344928): this shouldn't be neccessary
81+
Fantom.runWorkLoop();
82+
} else {
83+
expect(viewElement.getBoundingClientRect().x).toBe(0);
84+
Fantom.runWorkLoop(); // Animated still schedules a React state update for synchronisation to shadow tree
85+
}
7786

78-
// TODO: this shouldn't be needed but C++ Animated still schedules a React state update
79-
// for synchronisation, even though it doesn't need to.
80-
Fantom.runWorkLoop();
8187
expect(viewElement.getBoundingClientRect().x).toBe(100);
8288
});
8389

@@ -188,7 +194,7 @@ test('animated opacity', () => {
188194
0,
189195
);
190196

191-
// TODO: this shouldn't be neccessary but C++ Animated still schedules a React state update.
197+
// TODO(T223344928): this shouldn't be neccessary with cxxNativeAnimatedRemoveJsSync:true
192198
Fantom.runWorkLoop();
193199

194200
expect(root.getRenderedOutput({props: ['opacity']}).toJSX()).toEqual(
@@ -262,12 +268,18 @@ test('moving box by 50 points with offset 10', () => {
262268
.translateX,
263269
).toBeCloseTo(60, 0.001);
264270

265-
expect(root.getRenderedOutput({props: ['transform']}).toJSX()).toEqual(
266-
<rn-view transform='[{"translateX": 60.000000}]' />,
267-
);
268-
269-
// TODO: this shouldn't be neccessary but C++ Animated still schedules a React state update.
270-
Fantom.runWorkLoop();
271+
if (ReactNativeFeatureFlags.cxxNativeAnimatedRemoveJsSync()) {
272+
expect(root.getRenderedOutput({props: ['transform']}).toJSX()).toEqual(
273+
<rn-view transform='[{"translateX": 60.000000}]' />,
274+
);
275+
// TODO(T223344928): this shouldn't be neccessary
276+
Fantom.runWorkLoop();
277+
} else {
278+
expect(root.getRenderedOutput({props: ['transform']}).toJSX()).toEqual(
279+
<rn-view transform="[]" />,
280+
);
281+
Fantom.runWorkLoop(); // Animated still schedules a React state update for synchronisation to shadow tree
282+
}
271283

272284
expect(root.getRenderedOutput({props: ['transform']}).toJSX()).toEqual(
273285
<rn-view transform='[{"translateX": 60.000000}]' />, // // must include offset.
@@ -360,7 +372,7 @@ describe('Value.flattenOffset', () => {
360372

361373
expect(transform.translateY).toBeCloseTo(40, 0.001);
362374

363-
// TODO: this shouldn't be neccessary.
375+
// TODO(T223344928): this shouldn't be neccessary with cxxNativeAnimatedRemoveJsSync:true
364376
Fantom.runWorkLoop();
365377
});
366378
});
@@ -459,7 +471,7 @@ describe('Value.extractOffset', () => {
459471
// Previously we set offset to 35. The final value is 35.
460472
expect(transform.translateY).toBeCloseTo(35, 0.001);
461473

462-
// TODO: this shouldn't be neccessary.
474+
// TODO(T223344928): this shouldn't be neccessary with cxxNativeAnimatedRemoveJsSync:true
463475
Fantom.runWorkLoop();
464476
});
465477
});

packages/react-native/Libraries/Animated/animations/Animation.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import type AnimatedNode from '../nodes/AnimatedNode';
1313
import type AnimatedValue from '../nodes/AnimatedValue';
1414

1515
import NativeAnimatedHelper from '../../../src/private/animated/NativeAnimatedHelper';
16+
import * as ReactNativeFeatureFlags from '../../../src/private/featureflags/ReactNativeFeatureFlags';
1617
import AnimatedProps from '../nodes/AnimatedProps';
1718

1819
export type EndResult = {
@@ -149,8 +150,15 @@ export default class Animation {
149150
if (value != null) {
150151
animatedValue.__onAnimatedValueUpdateReceived(value, offset);
151152

152-
if (this.__isLooping === true) {
153-
return;
153+
if (
154+
!(
155+
ReactNativeFeatureFlags.cxxNativeAnimatedEnabled() &&
156+
ReactNativeFeatureFlags.cxxNativeAnimatedRemoveJsSync()
157+
)
158+
) {
159+
if (this.__isLooping === true) {
160+
return;
161+
}
154162
}
155163

156164
// Once the JS side node is synced with the updated values, trigger an

packages/react-native/ReactCxxPlatform/react/renderer/animated/NativeAnimatedNodesManager.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <folly/json.h>
1111
#include <glog/logging.h>
1212
#include <react/debug/react_native_assert.h>
13+
#include <react/featureflags/ReactNativeFeatureFlags.h>
1314
#include <react/profiling/perfetto.h>
1415
#include <react/renderer/animated/drivers/AnimationDriver.h>
1516
#include <react/renderer/animated/drivers/AnimationDriverUtils.h>
@@ -658,7 +659,9 @@ bool NativeAnimatedNodesManager::onAnimationFrame(double timestamp) {
658659

659660
if (driver->getIsComplete()) {
660661
hasFinishedAnimations = true;
661-
finishedAnimationValueNodes.insert(driver->getAnimatedValueTag());
662+
if (ReactNativeFeatureFlags::cxxNativeAnimatedRemoveJsSync()) {
663+
finishedAnimationValueNodes.insert(driver->getAnimatedValueTag());
664+
}
662665
}
663666
}
664667

packages/react-native/src/private/animated/createAnimatedPropsHook.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,13 @@ export default function createAnimatedPropsHook(
132132
if (node.__isNative) {
133133
// Check 2: this is an animation driven by native.
134134
// In native driven animations, this callback is only called once the animation completes.
135-
if (isFabricNode) {
135+
if (
136+
isFabricNode &&
137+
!(
138+
ReactNativeFeatureFlags.cxxNativeAnimatedEnabled() &&
139+
ReactNativeFeatureFlags.cxxNativeAnimatedRemoveJsSync()
140+
)
141+
) {
136142
// Call `scheduleUpdate` to synchronise Fiber and Shadow tree.
137143
// Must not be called in Paper.
138144
scheduleUpdate();

0 commit comments

Comments
 (0)