@samitouri / QOS-React-2 / commits / 26ba38ae4b

[EnterLeaveEventPlugin] Fix bug when dealing with unhandled DOM nodes (#17006)

Dominic Gannaway committed Oct 3, 2019 at 23:35 UTC 26ba38ae4b65375b97b561ec2d6a58ef597647ed
2 files changed +60 -1
packages/react-dom/src/events/EnterLeaveEventPlugin.js
+9 -1
@@ -42,6 +42,12 @@ const eventTypes = {
42 },
43 };
44
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 +
51 const EnterLeaveEventPlugin = {
52 eventTypes: eventTypes,
53
@@ -163,9 +169,11 @@ const EnterLeaveEventPlugin = {
169
170 accumulateEnterLeaveDispatches(leave, enter, from, to);
171
166 - if (isOutEvent && from && nativeEventTarget !== fromNode) {
172 + if (nativeEvent === lastNativeEvent) {
173 + lastNativeEvent = null;
174 return [leave];
175 }
176 + lastNativeEvent = nativeEvent;
177
178 return [leave, enter];
179 },
packages/react-dom/src/events/__tests__/EnterLeaveEventPlugin-test.js
+51
@@ -185,4 +185,55 @@ describe('EnterLeaveEventPlugin', () => {
185
186 ReactDOM.render(<Parent />, container);
187 });
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 + });
239 });