diff --git a/fixtures/dom/src/components/fixtures/mouse-events/index.js b/fixtures/dom/src/components/fixtures/mouse-events/index.js
index 4c121bf094790..3624d4e837b2f 100644
--- a/fixtures/dom/src/components/fixtures/mouse-events/index.js
+++ b/fixtures/dom/src/components/fixtures/mouse-events/index.js
@@ -1,5 +1,6 @@
import FixtureSet from '../../FixtureSet';
import MouseMovement from './mouse-movement';
+import MouseEnter from './mouse-enter';
const React = window.React;
@@ -8,6 +9,7 @@ class MouseEvents extends React.Component {
return (
+
);
}
diff --git a/fixtures/dom/src/components/fixtures/mouse-events/mouse-enter.js b/fixtures/dom/src/components/fixtures/mouse-events/mouse-enter.js
new file mode 100644
index 0000000000000..c0fbcbda6a432
--- /dev/null
+++ b/fixtures/dom/src/components/fixtures/mouse-events/mouse-enter.js
@@ -0,0 +1,73 @@
+import TestCase from '../../TestCase';
+
+const React = window.React;
+const ReactDOM = window.ReactDOM;
+
+const MouseEnter = () => {
+ const containerRef = React.useRef();
+
+ React.useEffect(function() {
+ const hostEl = containerRef.current;
+ ReactDOM.render(, hostEl, () => {
+ ReactDOM.render(, hostEl.childNodes[1]);
+ });
+ }, []);
+
+ return (
+
+
+ Mouse enter the boxes below, from different borders
+
+
+ Mouse enter call count should equal to 1;
+ Issue{' '}
+
+ #16763
+ {' '}
+ should not happen.
+
+
+
+
+ );
+};
+
+const MouseEnterDetect = () => {
+ const [log, setLog] = React.useState({});
+ const firstEl = React.useRef();
+ const siblingEl = React.useRef();
+
+ const onMouseEnter = e => {
+ const timeStamp = e.timeStamp;
+ setLog(log => {
+ const callCount = 1 + (log.timeStamp === timeStamp ? log.callCount : 0);
+ return {
+ timeStamp,
+ callCount,
+ };
+ });
+ };
+
+ return (
+
+
+ Mouse enter call count: {log.callCount || ''}
+
+
+
+ );
+};
+
+export default MouseEnter;
diff --git a/packages/react-dom/src/events/EnterLeaveEventPlugin.js b/packages/react-dom/src/events/EnterLeaveEventPlugin.js
index 4133006488171..aca141225282e 100644
--- a/packages/react-dom/src/events/EnterLeaveEventPlugin.js
+++ b/packages/react-dom/src/events/EnterLeaveEventPlugin.js
@@ -146,6 +146,10 @@ const EnterLeaveEventPlugin = {
accumulateEnterLeaveDispatches(leave, enter, from, to);
+ if (isOutEvent && from && nativeEventTarget !== fromNode) {
+ return [leave];
+ }
+
return [leave, enter];
},
};
diff --git a/packages/react-dom/src/events/__tests__/EnterLeaveEventPlugin-test.js b/packages/react-dom/src/events/__tests__/EnterLeaveEventPlugin-test.js
index 33dd3e964ee40..b8bda1c67fe9f 100644
--- a/packages/react-dom/src/events/__tests__/EnterLeaveEventPlugin-test.js
+++ b/packages/react-dom/src/events/__tests__/EnterLeaveEventPlugin-test.js
@@ -134,4 +134,55 @@ describe('EnterLeaveEventPlugin', () => {
expect(childEnterCalls).toBe(1);
expect(parentEnterCalls).toBe(0);
});
+
+ // Test for https://github.com/facebook/react/issues/16763.
+ it('should call mouseEnter once from sibling rendered inside a rendered component', done => {
+ const mockFn = jest.fn();
+
+ class Parent extends React.Component {
+ constructor(props) {
+ super(props);
+ this.parentEl = React.createRef();
+ }
+
+ componentDidMount() {
+ ReactDOM.render(, this.parentEl.current);
+ }
+
+ render() {
+ return
;
+ }
+ }
+
+ class MouseEnterDetect extends React.Component {
+ constructor(props) {
+ super(props);
+ this.firstEl = React.createRef();
+ this.siblingEl = React.createRef();
+ }
+
+ componentDidMount() {
+ this.siblingEl.current.dispatchEvent(
+ new MouseEvent('mouseout', {
+ bubbles: true,
+ cancelable: true,
+ relatedTarget: this.firstEl.current,
+ }),
+ );
+ expect(mockFn.mock.calls.length).toBe(1);
+ done();
+ }
+
+ render() {
+ return (
+
+
+
+
+ );
+ }
+ }
+
+ ReactDOM.render(, container);
+ });
});