Skip to content

Commit 7887412

Browse files
authored
fix: prevent negative listener count in AnimatedColor
Overrode addListener, removeListener, and removeAllListeners to mirror AnimatedValueXY architecture and utilize a local listeners map. This handles edge cases like calling removeListener after __detach seamlessly.
1 parent 59def0a commit 7887412

1 file changed

Lines changed: 38 additions & 1 deletion

File tree

packages/react-native/Libraries/Animated/nodes/AnimatedColor.js

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,14 @@ export default class AnimatedColor extends AnimatedWithChildren {
139139
nativeColor: ?NativeColorValue;
140140

141141
_suspendCallbacks: number = 0;
142+
_listeners: {
143+
[key: string]: {
144+
r: string,
145+
g: string,
146+
b: string,
147+
a: string,
148+
},
149+
} = {};
142150

143151
constructor(valueIn?: InputValue, config?: ?AnimatedColorConfig) {
144152
super(config);
@@ -171,6 +179,35 @@ export default class AnimatedColor extends AnimatedWithChildren {
171179
}
172180
}
173181

182+
addListener(callback: ColorListenerCallback): string {
183+
const id = String(Math.random());
184+
const jointCallback = () => callback(this.__getValue());
185+
this._listeners[id] = {
186+
r: this.r.addListener(jointCallback),
187+
g: this.g.addListener(jointCallback),
188+
b: this.b.addListener(jointCallback),
189+
a: this.a.addListener(jointCallback),
190+
};
191+
return id;
192+
}
193+
194+
removeListener(id: string): void {
195+
if (!this._listeners[id]) {
196+
// Already removed (e.g. after __detach / removeAllListeners) — safe no-op
197+
return;
198+
}
199+
this.r.removeListener(this._listeners[id].r);
200+
this.g.removeListener(this._listeners[id].g);
201+
this.b.removeListener(this._listeners[id].b);
202+
this.a.removeListener(this._listeners[id].a);
203+
delete this._listeners[id];
204+
}
205+
206+
removeAllListeners(): void {
207+
Object.keys(this._listeners).forEach(id => this.removeListener(id));
208+
this._listeners = {};
209+
}
210+
174211
/**
175212
* Directly set the value. This will stop any animations running on the value
176213
* and update all the bound properties.
@@ -247,7 +284,7 @@ export default class AnimatedColor extends AnimatedWithChildren {
247284
}
248285

249286
/**
250-
* Sets the offset value to the base value, and resets the base value to
287+
* Sets the offset value to the solvency value, and resets the base value to
251288
* zero. The final output of the value is unchanged.
252289
*/
253290
extractOffset(): void {

0 commit comments

Comments
 (0)