Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Component retains old event listener after its content changes #1613

Closed
v4n opened this issue Feb 10, 2017 · 18 comments
Closed

Component retains old event listener after its content changes #1613

v4n opened this issue Feb 10, 2017 · 18 comments
Labels
Type: Bug For bugs and any other unexpected breakage

Comments

@v4n
Copy link

v4n commented Feb 10, 2017

I have the following component with a span that should only call unclick when it's clicked but calls click and unclick.

function component() {
  if (...) {
    return <div>
      <div></div>
      <div onclick={click} class="click-me">
        Click me
      </div
    </div>
  }

  return <div>
    <div></div>
    <div class="unclick-me">
      <span onclick={unclick}>Unclick</span>
    </div>
  </div>
}

Here is a running example:
https://codepen.io/v4n/pen/bgQNGW?editors=0010

@tivac
Copy link
Contributor

tivac commented Feb 10, 2017

Mithril redraws after the unclick function runs because of the m.mount, and it seems like that happens faster than the event can bubble. I verified in the chrome debugger that there's no stale click handler on the .unclick-me element, just on the <span>.

listener-removed

Stopping event propagation in the unclick handler will also prevent the click handler from being re-triggered.

@tivac
Copy link
Contributor

tivac commented Feb 10, 2017

Here's a smaller repro: https://jsbin.com/nesehey/8/edit?js,output

It attaches a non-mithril attribute to the outer node which persists between both states. Not sure if that's useful, but it is interesting.

@pygy
Copy link
Member

pygy commented Feb 10, 2017

Another argument for #1592

Conspiracy theory: I'm starting to think @lhorie is actually a secret Zalgo priest, luring unsuspecting coders to feed his master. The Zalgo article was mentioned in #1, and Leo is usually convinced by rational arguments, yet, maybe-sync redraws are still there, justified as an optimization, and calls for always async are ignored...

Sync redraws win at best 16 ms, 8 on average on platforms that support rAF... UI changes that happen within 100ms are percieved as instantaneous... Incorrect code is infinitely slower, anyway.

@ilsenem
Copy link

ilsenem commented Feb 10, 2017

https://codepen.io/ilsenem/pen/JEeYzx?editors=0010

This behavior is not the case in v0.2.3 with the same code base.

It may be fast redraw as @tivac mentioned.

@dead-claudia
Copy link
Member

@pygy

Conspiracy theory: I'm starting to think @lhorie is actually a secret Zalgo priest [...]

He must've been teaming up with this guy at one point! 😆


In reality, I think it took the monster of 0.2 for him to start becoming a little more conservative when it comes to architecting the code. That old code base was almost the epitome of Zalgo. There was enough spaghetti logic to make improvement nearly impossible without breaking everything, over and over and over. (And this is why it wound up with a full revert - it was a read-only code base, where only the slightest change in seemingly unrelated areas caused an entire mountain to topple.)

@dead-claudia
Copy link
Member

As for the current rewrite, I just haven't had the chance to take a decent look at it for performance tweaks.

@barneycarroll
Copy link
Member

@isiahmeadows this particular variant of Zalgo results from a consumer API contract that occasionally deviates from otherwise predictable resolution expectations - specifically: mostly asynchronous but sometimes synchronous. Like the unreliable attempt by m.request to delay redraw until all derivative thens have resolved, the 'occasionally sync' redraw is a whimsical feature with no use case, no documentation, and the potential to create incredibly confusing and difficult to debug expectation shortfalls.

@pygy
Copy link
Member

pygy commented Feb 21, 2017

I'd say that here, Mithril unleashes Zalgo on itself by calling said public API in the event handler...

A cheap "fix" would be to setTimeout(m.redraw) in the event handler wrapper...

@v4n
Copy link
Author

v4n commented Feb 21, 2017

@pygy based on your early comment, I'm assuming #1592 would fix this bug?

@isiahmeadows @tivac mind adding a bug label to this if you guys agree it's?

@pygy
Copy link
Member

pygy commented Feb 21, 2017

@v4n it would, but I'd rather have #1643 merged first. Both PRs modify the tests in a way that causes conflicts and #1592 will be easier to rework than #1643. Adding a node there...

@pygy
Copy link
Member

pygy commented Feb 21, 2017

@v4n if this is blocking you, you can add

e.redraw = false
setTimeout(m.redraw)

to the problematic handlers

Live: https://codepen.io/anon/pen/EZqrMQ?editors=0010

@dead-claudia dead-claudia added the Type: Bug For bugs and any other unexpected breakage label Feb 22, 2017
@dead-claudia
Copy link
Member

dead-claudia commented Mar 27, 2017

Found a suspect: this branch should have an else.

@pygy
Copy link
Member

pygy commented Mar 27, 2017

@isiahmeadows isn't covered here?

@dead-claudia
Copy link
Member

No, but my initial suspicion is wrong.

@dead-claudia
Copy link
Member

The problem is that the inexistence isn't being handled correctly.

@dead-claudia
Copy link
Member

Another suspect: this function should clean up removed attributes as well.

@dead-claudia
Copy link
Member

It's not a 1.1 blocker, though (although it still repros).

@dead-claudia
Copy link
Member

Closing in favor of #1804.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Bug For bugs and any other unexpected breakage
Projects
None yet
Development

No branches or pull requests

6 participants