Skip to content

Clean up event listeners from previous renders#618

Merged
hustcc merged 5 commits into
hustcc:masterfrom
gggritso:fix/unbind-listeners
Jan 21, 2026
Merged

Clean up event listeners from previous renders#618
hustcc merged 5 commits into
hustcc:masterfrom
gggritso:fix/unbind-listeners

Conversation

@gggritso

@gggritso gggritso commented Jan 5, 2026

Copy link
Copy Markdown
Contributor

Fixes #615, which I introduced in #613, apologies!

The code calls instance.off(eventName, events[eventName]) where events is the new onEvents passed on the current component render. This is incorrect! The handlers on the instance are not what was passed on onEvents, they're wrapped in a function:

        instance.on(eventName, (param) => { // This is the actual bound listener
          func(param, instance); // `func` is what was passed in `onEvents`
        });

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 Promise is used internally, maybe others have better ideas?

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.
@coveralls

coveralls commented Jan 5, 2026

Copy link
Copy Markdown

Coverage Status

coverage: 94.737%. remained the same
when pulling edde2b7 on gggritso:fix/unbind-listeners
into 6bbc4c5 on hustcc:master.

@gggritso gggritso marked this pull request as ready for review January 5, 2026 22:43
@gggritso

gggritso commented Jan 5, 2026

Copy link
Copy Markdown
Contributor Author

@hustcc apologies for the disruption! Would you mind taking a look at this PR?

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 onEvents property
  • Modified bindEvents to store references to the actual wrapped handlers
  • Replaced offEvents with unbindEvents that 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.

Comment thread src/core.tsx Outdated
@hustcc hustcc merged commit 2346edc into hustcc:master Jan 21, 2026
2 checks passed
@hustcc

hustcc commented Jan 21, 2026

Copy link
Copy Markdown
Owner
  • echarts-for-react@3.0.6 Have a try!

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.
@sanderdesnaijer sanderdesnaijer mentioned this pull request Jan 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Old event handlers are not removed when they are replaced in version 3.0.5

4 participants