Animated: Change onEnd to Private Property (#46721)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/46721

Currently, the `Animation` class (from Animated) defines an unofficially protected `__onEnd` property that subclasses are expected to populate. However, subclasses are expected to *not* invoke `__onEnd`, but instead call `__debouncedOnEnd`.

In order to make this code less fragile, this commit refactors the `Animation` class and its subclasses so that `onEnd` is stored in a private property and initialized by the `start` method in the `Animation` parent class. Now, the only way to invoke the `onEnd` callback is by calling `__debouncedOnEnd`.

The subclasses have been adjusted to call the `start` superclass method to initialize this.

Changelog:
[General][Changed] - The `Animation` superclass no longer exposes `__onEnd` as a property. Subclasses must instead invoke `super.start(…)` in their `start()` implementation.

Reviewed By: javache

Differential Revision: D63572063

fbshipit-source-id: 221153ca890c67c59713d607032536f57d7a5b0a
This commit is contained in:
Tim Yung
2024-10-02 02:07:00 -07:00
committed by Facebook GitHub Bot
parent fd355308fa
commit b3fe06b268
5 changed files with 13 additions and 8 deletions
@@ -36,9 +36,10 @@ let startNativeAnimationNextId = 1;
// Once an animation has been stopped or finished its course, it will
// not be reused.
export default class Animation {
#onEnd: ?EndCallback;
__active: boolean;
__isInteraction: boolean;
__onEnd: ?EndCallback;
__iterations: number;
__isLooping: ?boolean;
@@ -50,7 +51,9 @@ export default class Animation {
onEnd: ?EndCallback,
previousAnimation: ?Animation,
animatedValue: AnimatedValue,
): void {}
): void {
this.#onEnd = onEnd;
}
stop(): void {
if (this._nativeId) {
@@ -66,8 +69,8 @@ export default class Animation {
// Helper function for subclasses to make sure onEnd is only called once.
__debouncedOnEnd(result: EndResult): void {
const onEnd = this.__onEnd;
this.__onEnd = null;
const onEnd = this.#onEnd;
this.#onEnd = null;
onEnd && onEnd(result);
}
@@ -79,11 +79,12 @@ export default class DecayAnimation extends Animation {
previousAnimation: ?Animation,
animatedValue: AnimatedValue,
): void {
super.start(fromValue, onUpdate, onEnd, previousAnimation, animatedValue);
this.__active = true;
this._lastValue = fromValue;
this._fromValue = fromValue;
this._onUpdate = onUpdate;
this.__onEnd = onEnd;
this._startTime = Date.now();
if (!this._useNativeDriver && animatedValue.__isNative === true) {
@@ -202,12 +202,13 @@ export default class SpringAnimation extends Animation {
previousAnimation: ?Animation,
animatedValue: AnimatedValue,
): void {
super.start(fromValue, onUpdate, onEnd, previousAnimation, animatedValue);
this.__active = true;
this._startPosition = fromValue;
this._lastPosition = this._startPosition;
this._onUpdate = onUpdate;
this.__onEnd = onEnd;
this._lastTime = Date.now();
this._frameTime = 0.0;
@@ -107,10 +107,11 @@ export default class TimingAnimation extends Animation {
previousAnimation: ?Animation,
animatedValue: AnimatedValue,
): void {
super.start(fromValue, onUpdate, onEnd, previousAnimation, animatedValue);
this.__active = true;
this._fromValue = fromValue;
this._onUpdate = onUpdate;
this.__onEnd = onEnd;
const start = () => {
if (!this._useNativeDriver && animatedValue.__isNative === true) {
@@ -427,7 +427,6 @@ export type AnimationConfig = {
declare export default class Animation {
__active: boolean;
__isInteraction: boolean;
__onEnd: ?EndCallback;
__iterations: number;
__isLooping: ?boolean;
_nativeId: number;