Mike
Mike

Reputation: 12819

React onTransitionEnd event gets called frequently

I have React code like this:

handleTransitionEnd() {
    console.log('ended');
}

<div onTransitionEnd={(ev) => this.handleTransitionEnd(ev)}....

The peculiar thing is that my logs are filling up with ended. Even if I don't have any transition css logic tied to the element at all. It seems to be firing on every state change or re render. Is this normal? I would expect it to only fire when a css transition ends.

Is there some other way this callback should be achieved?

Thanks

UPDATE:

here is a sandbox showing some strangeness: https://codesandbox.io/s/vy5wwyq5v3

Clicking the first button causes the callback to be called 3 times, then if you click the second button it gets called another 2 times even tho a transition doesn't happen. My app is even more extreme than this with it getting called a lot more often.

Upvotes: 3

Views: 16780

Answers (2)

Armel Chesnais
Armel Chesnais

Reputation: 260

To add on to what dabs said in his answer, the transitionend event bubbles. This means if any children of your element have transitions on them, they will trigger the transitionend event on themselves, then bubble up to their parent, triggering on each of them, including the current element that you have the listener on.

A simple way to check that you're only running your logic for the element your listener is on is to compare e.target and e.currentTarget like so:

onTransitionEnd={e => {
if ( e.target === e.currentTarget ) {
  // your logic here
}}

e.target is the element that starts the event, which can be one of the children, for example, not just the element with the listener on it. e.currentTarget however always points to the element that has the listener on it, regardless of if it initiated the event or not. By comparing the two, you can check that you're only running logic when it's the element with the listener on it that initiated it.

Upvotes: 1

dabs
dabs

Reputation: 51

The css transition being used transition: "all 3s" is causing transitions on multiple properties, not just margin-left.

In the example provided, outline-color and outline-width were transitioned as well. They were then transitioned again when clicking anywhere else (not just on the second button).

You can see this by checking the event:

onTransitionEnd={e => {
  e.persist();                 // see: https://reactjs.org/docs/events.html#event-pooling
  console.log(e.propertyName);
}}

The css transition could be more specific: transition: "margin-left 3s" to avoid this. Alternatively, test e.propertyName for the desired case.

Upvotes: 5

Related Questions