Clean up event listeners from previous renders#618
Merged
Conversation
This makes it possible to dispatch legend events for testing.
This verifies the bug by adding a failing test case. On re-render there are two event listeners attached to the chart instance, there should be only one!
Keep track of the handlers added to the current instance. Unbind them before binding new events.
Contributor
Author
|
@hustcc apologies for the disruption! Would you mind taking a look at this PR? |
There was a problem hiding this comment.
Pull request overview
This pull request fixes a bug where event listeners from previous renders were not being properly cleaned up, leading to multiple handlers being attached to the same event. The issue was introduced in PR #613 where the cleanup code attempted to unbind handlers using the original function references, but the actual handlers bound to the ECharts instance were wrapped functions.
Changes:
- Added tracking of wrapped event handlers in a private
onEventsproperty - Modified
bindEventsto store references to the actual wrapped handlers - Replaced
offEventswithunbindEventsthat correctly unbinds using stored handler references - Added test to verify that only one handler remains bound after re-render
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| src/core.tsx | Added onEvents property to track wrapped handlers; modified bindEvents to store handler references; replaced offEvents with unbindEvents that correctly cleans up stored handlers |
| tests/charts/simple-spec.tsx | Added test data (legend and second series) and new test case verifying proper event handler cleanup on re-render |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Owner
|
gggritso
added a commit
to getsentry/sentry
that referenced
this pull request
Jan 21, 2026
…#106678) Fixes DAIN-1144 Upgrades echarts-for-react from 3.0.5 to 3.0.6 to fix an issue where legend event listeners were accumulating on component re-renders. The library was attempting to unbind listeners using the original function references, but the actual bound handlers were wrapped functions, causing old listeners to remain attached. This led to dashboard widget legends repeatedly updating the URL because multiple stale handlers were firing on each interaction. Version 3.0.6 fixes this by properly tracking the wrapped handler references and unbinding them before attaching new ones. See hustcc/echarts-for-react#618 for details.
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #615, which I introduced in #613, apologies!
The code calls
instance.off(eventName, events[eventName])whereeventsis the newonEventspassed on the current component render. This is incorrect! The handlers on the instance are not what was passed ononEvents, they're wrapped in a function:In this PR, I'm keeping track of the actual handlers that were bound on the previous render, and unbinding them correctly on subsequent re-renders.
Other approaches are possible. The most obvious one is to revert to running
instance.off(eventName)but this will re-create the bug in #613. We can avoid the bug by manually re-binding the "finished" event if the component instance is still initializing.The test for this case is nasty, lots of async work and timeouts. Hard to avoid because
Promiseis used internally, maybe others have better ideas?