@samitouri / QOS-React-2 / commits / ad8211d96a

Add more non-React events to the priority list (#20774)

* Add a test for mouseover being continuous * Add more non-React events to the priority list

Dan Abramov committed Feb 9, 2021 at 22:04 UTC ad8211d96a7990a91d4f6c9915b8b30566c3c0af
3 files changed +90
packages/react-dom/src/__tests__/ReactDOMNativeEventHeuristic-test.js
+66
@@ -13,6 +13,7 @@ let React;
13
14 let ReactDOM;
15 let Scheduler;
16 +let act;
17
18 describe('ReactDOMNativeEventHeuristic-test', () => {
19 let container;
@@ -23,6 +24,7 @@ describe('ReactDOMNativeEventHeuristic-test', () => {
24 React = require('react');
25 ReactDOM = require('react-dom');
26 Scheduler = require('scheduler');
27 + act = require('react-dom/test-utils').unstable_concurrentAct;
28
29 document.body.appendChild(container);
30 });
@@ -225,4 +227,68 @@ describe('ReactDOMNativeEventHeuristic-test', () => {
227 // Therefore the form should have been submitted.
228 expect(formSubmitted).toBe(true);
229 });
230 +
231 + // @gate experimental
232 + // @gate enableDiscreteEventMicroTasks && enableNativeEventPriorityInference
233 + it('mouse over should be user-blocking but not discrete', async () => {
234 + const root = ReactDOM.unstable_createRoot(container);
235 +
236 + const target = React.createRef(null);
237 + function Foo() {
238 + const [isHover, setHover] = React.useState(false);
239 + React.useLayoutEffect(() => {
240 + target.current.onmouseover = () => setHover(true);
241 + });
242 + return <div ref={target}>{isHover ? 'hovered' : 'not hovered'}</div>;
243 + }
244 +
245 + await act(async () => {
246 + root.render(<Foo />);
247 + });
248 + expect(container.textContent).toEqual('not hovered');
249 +
250 + await act(async () => {
251 + const mouseOverEvent = document.createEvent('MouseEvents');
252 + mouseOverEvent.initEvent('mouseover', true, true);
253 + dispatchAndSetCurrentEvent(target.current, mouseOverEvent);
254 +
255 + // 3s should be enough to expire the updates
256 + Scheduler.unstable_advanceTime(3000);
257 + expect(Scheduler).toFlushExpired([]);
258 + expect(container.textContent).toEqual('hovered');
259 + });
260 + });
261 +
262 + // @gate experimental
263 + // @gate enableDiscreteEventMicroTasks && enableNativeEventPriorityInference
264 + it('mouse enter should be user-blocking but not discrete', async () => {
265 + const root = ReactDOM.unstable_createRoot(container);
266 +
267 + const target = React.createRef(null);
268 + function Foo() {
269 + const [isHover, setHover] = React.useState(false);
270 + React.useLayoutEffect(() => {
271 + target.current.onmouseenter = () => setHover(true);
272 + });
273 + return <div ref={target}>{isHover ? 'hovered' : 'not hovered'}</div>;
274 + }
275 +
276 + await act(async () => {
277 + root.render(<Foo />);
278 + });
279 + expect(container.textContent).toEqual('not hovered');
280 +
281 + await act(async () => {
282 + // Note: React does not use native mouseenter/mouseleave events
283 + // but we should still correctly determine their priority.
284 + const mouseEnterEvent = document.createEvent('MouseEvents');
285 + mouseEnterEvent.initEvent('mouseenter', true, true);
286 + dispatchAndSetCurrentEvent(target.current, mouseEnterEvent);
287 +
288 + // 3s should be enough to expire the updates
289 + Scheduler.unstable_advanceTime(3000);
290 + expect(Scheduler).toFlushExpired([]);
291 + expect(container.textContent).toEqual('hovered');
292 + });
293 + });
294 });
packages/react-dom/src/events/DOMEventNames.js
+10
@@ -17,6 +17,8 @@ export type DOMEventName =
17 // 'animationend |
18 // 'animationstart' |
19 | 'beforeblur' // Not a real event. This is used by event experiments.
20 + | 'beforeinput'
21 + | 'blur'
22 | 'canplay'
23 | 'canplaythrough'
24 | 'cancel'
@@ -44,9 +46,12 @@ export type DOMEventName =
46 | 'encrypted'
47 | 'ended'
48 | 'error'
49 + | 'focus'
50 | 'focusin'
51 | 'focusout'
52 + | 'fullscreenchange'
53 | 'gotpointercapture'
54 + | 'hashchange'
55 | 'input'
56 | 'invalid'
57 | 'keydown'
@@ -58,6 +63,8 @@ export type DOMEventName =
63 | 'loadedmetadata'
64 | 'lostpointercapture'
65 | 'mousedown'
66 + | 'mouseenter'
67 + | 'mouseleave'
68 | 'mousemove'
69 | 'mouseout'
70 | 'mouseover'
@@ -74,12 +81,15 @@ export type DOMEventName =
81 | 'pointerout'
82 | 'pointerover'
83 | 'pointerup'
84 + | 'popstate'
85 | 'progress'
86 | 'ratechange'
87 | 'reset'
88 | 'scroll'
89 | 'seeked'
90 | 'seeking'
91 + | 'select'
92 + | 'selectstart'
93 | 'selectionchange'
94 | 'stalled'
95 | 'submit'
packages/react-dom/src/events/ReactDOMEventListener.js
+14
@@ -397,6 +397,16 @@ export function getEventPriority(domEventName: DOMEventName): * {
397 // eslint-disable-next-line no-fallthrough
398 case 'beforeblur':
399 case 'afterblur':
400 + // Not used by React but could be by user code:
401 + // eslint-disable-next-line no-fallthrough
402 + case 'beforeinput':
403 + case 'blur':
404 + case 'fullscreenchange':
405 + case 'focus':
406 + case 'hashchange':
407 + case 'popstate':
408 + case 'select':
409 + case 'selectstart':
410 return InputDiscreteLanePriority;
411 case 'drag':
412 case 'dragenter':
@@ -413,6 +423,10 @@ export function getEventPriority(domEventName: DOMEventName): * {
423 case 'toggle':
424 case 'touchmove':
425 case 'wheel':
426 + // Not used by React but could be by user code:
427 + // eslint-disable-next-line no-fallthrough
428 + case 'mouseenter':
429 + case 'mouseleave':
430 return InputContinuousLanePriority;
431 default:
432 return DefaultLanePriority;