React: In React 16, onMouseEnter is triggered an extra time when entering a new child

Created on 28 Sep 2017  ·  14Comments  ·  Source: facebook/react

版本(versions):
[email protected]
[email protected]

描述(description):
给父级别绑定 onMouseEnter 事件。在首次渲染后,鼠标移入新渲染进去的子元素会触发父元素的 onMouseEnter 事件。

示例(demo):

import React, {Component} from 'react';

class Demo extends Component {
    constructor(prop) {
        super(prop);
        this.enter = this.enter.bind(this)
        this.state = {
            flag: false
        }
    }
    enter(event) {
        console.log(event.nativeEvent);
        console.log("enter")
    }
    click() {
        this.setState({flag:!this.state.flag})
    }
    render() {
        let old = {
            height: "100px",
            width: "100px",
            border: "1px solid #6dbbff"
        };
        let aa = {
            height: "100px",
            width: "100px",
            border: "1px solid red"
        };
        let content = {
            border: "1px solid black",
            display: "flex",
            padding:"10px"
        }
        return(
            <div>
                <div style={content} onMouseEnter={this.enter}>
                    {this.state.a}
                    <div style={old}>old</div>
                    <div style={aa}>old</div>
                    {this.state.flag && <div style={aa}>new</div>}
                </div>
                <button onClick={this.click.bind(this)}>点我(click me)</button>
            </div>
        )
    }
}
Bug

Most helpful comment

(On the side note, how awesome is it that we speak different languages, and yet can understand each other with code? 😄 )

All 14 comments

@Sherryer Do you mean you want the click button to be free from the onMouseEnter event handler?

I can confirm I see the difference between 15 and 16 behavior. Maybe a bug.

(On the side note, how awesome is it that we speak different languages, and yet can understand each other with code? 😄 )

@gaearon Hey Dan, I created a fiddle about this issue.

https://jsfiddle.net/cyan3/k28vxab1/

If you click the button, and hover on the right most div('new'), it will trigger the onmouseenter event twice. It seems to me a bug.

If you need any help, I'm much willing to do something.

I don’t really have any idea about where it’s coming from. So you can start looking into how the code path for that event is different (maybe in EnterLeavePlugin) between 15 and 16.

Another possible place is here: https://github.com/facebook/react/blob/master/src/renderers/shared/shared/ReactTreeTraversal.js#L112

There are a few enter/leave issues piling up maybe it's worth getting the switch to native events in there: https://github.com/facebook/react/pull/10269

To clarify, the behavior isn't that there are two enter events being dispatched on the same element; it's that the newly added element is _also_ dispatching an enter event that is being captured by the parent's onMouseEnter handler. If you mouse over very slowly you'll see the first event fires when your mouse enters the parent (black border) and the second fires when your mouse enters the new child (red border).

Another possible place is here: https://github.com/facebook/react/blob/master/src/renderers/shared/shared/ReactTreeTraversal.js#L112

@jquense this looks like part of the root issue. I'm seeing that for the child divs that aren't triggering enter events, to and from inside traverseEnterLeave are equal. With the newly added div, to and from are not equal, so it ends up populating the pathTo and pathFrom arrays and the event gets processed.

It’s a valid bug, please don’t close it.

React 16.1.0-beta has been released. Please update react, react-dom, and react-test-renderer (if you use it) to this version and let us know if it solved the issue! We’d appreciate if you could test before Monday when we plan to get 16.1.0 out.

It works great, thank you!

@cyan33 should you do event.stopPropagation(); in your enter function?

Was this page helpful?
0 / 5 - 0 ratings