Skip to content

Commit 26ba38a

Browse files
authored
[EnterLeaveEventPlugin] Fix bug when dealing with unhandled DOM nodes (#17006)
1 parent abedf17 commit 26ba38a

File tree

2 files changed

+60
-1
lines changed

2 files changed

+60
-1
lines changed

packages/react-dom/src/events/EnterLeaveEventPlugin.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ const eventTypes = {
4242
},
4343
};
4444

45+
// We track the lastNativeEvent to ensure that when we encounter
46+
// cases where we process the same nativeEvent multiple times,
47+
// which can happen when have multiple ancestors, that we don't
48+
// duplicate enter
49+
let lastNativeEvent;
50+
4551
const EnterLeaveEventPlugin = {
4652
eventTypes: eventTypes,
4753

@@ -163,9 +169,11 @@ const EnterLeaveEventPlugin = {
163169

164170
accumulateEnterLeaveDispatches(leave, enter, from, to);
165171

166-
if (isOutEvent && from && nativeEventTarget !== fromNode) {
172+
if (nativeEvent === lastNativeEvent) {
173+
lastNativeEvent = null;
167174
return [leave];
168175
}
176+
lastNativeEvent = nativeEvent;
169177

170178
return [leave, enter];
171179
},

packages/react-dom/src/events/__tests__/EnterLeaveEventPlugin-test.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,4 +185,55 @@ describe('EnterLeaveEventPlugin', () => {
185185

186186
ReactDOM.render(<Parent />, container);
187187
});
188+
189+
it('should call mouseEnter when pressing a non tracked React node', done => {
190+
const mockFn = jest.fn();
191+
192+
class Parent extends React.Component {
193+
constructor(props) {
194+
super(props);
195+
this.parentEl = React.createRef();
196+
}
197+
198+
componentDidMount() {
199+
ReactDOM.render(<MouseEnterDetect />, this.parentEl.current);
200+
}
201+
202+
render() {
203+
return <div ref={this.parentEl} />;
204+
}
205+
}
206+
207+
class MouseEnterDetect extends React.Component {
208+
constructor(props) {
209+
super(props);
210+
this.divRef = React.createRef();
211+
this.siblingEl = React.createRef();
212+
}
213+
214+
componentDidMount() {
215+
const attachedNode = document.createElement('div');
216+
this.divRef.current.appendChild(attachedNode);
217+
attachedNode.dispatchEvent(
218+
new MouseEvent('mouseout', {
219+
bubbles: true,
220+
cancelable: true,
221+
relatedTarget: this.siblingEl.current,
222+
}),
223+
);
224+
expect(mockFn.mock.calls.length).toBe(1);
225+
done();
226+
}
227+
228+
render() {
229+
return (
230+
<div ref={this.divRef}>
231+
<div ref={this.siblingEl} onMouseEnter={mockFn} />
232+
</div>
233+
);
234+
}
235+
}
236+
237+
ReactDOM.render(<Parent />, container);
238+
});
188239
});

0 commit comments

Comments
 (0)