Skip to content

Commit 754b8b4

Browse files
sebmarkbagetrueadm
authored andcommitted
Rename Chunks API to Blocks (facebook#18086)
Sounds like this is the name we're going with. This also helps us distinguish it from other "chunking" implementation details. Add Modern Event System fork Fix FIX FIX Refine comment Support handling of listening to comment nodes Update error codes FXI FXI Add test cases and revise traversal Fix Refactor twak Rename Address traversal of comment nodes Fix Fix
1 parent 8b596e0 commit 754b8b4

35 files changed

+1559
-246
lines changed

packages/react-debug-tools/src/ReactDebugHooks.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import {
2525
SimpleMemoComponent,
2626
ContextProvider,
2727
ForwardRef,
28-
Chunk,
28+
Block,
2929
} from 'shared/ReactWorkTags';
3030

3131
type CurrentDispatcherRef = typeof ReactSharedInternals.ReactCurrentDispatcher;
@@ -628,7 +628,7 @@ export function inspectHooksOfFiber(
628628
fiber.tag !== FunctionComponent &&
629629
fiber.tag !== SimpleMemoComponent &&
630630
fiber.tag !== ForwardRef &&
631-
fiber.tag !== Chunk
631+
fiber.tag !== Block
632632
) {
633633
throw new Error(
634634
'Unknown Fiber. Needs to be a function component to inspect hooks.',

packages/react-dom/src/__tests__/ReactBrowserEventEmitter-test.internal.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ let ReactDOMComponentTree;
1717
let listenToEvent;
1818
let ReactDOMEventListener;
1919
let ReactTestUtils;
20+
let ReactFeatureFlags;
2021

2122
let idCallOrder;
2223
const recordID = function(id) {
@@ -60,13 +61,20 @@ describe('ReactBrowserEventEmitter', () => {
6061
jest.resetModules();
6162
LISTENER.mockClear();
6263

64+
ReactFeatureFlags = require('shared/ReactFeatureFlags');
6365
EventPluginGetListener = require('legacy-events/getListener').default;
6466
EventPluginRegistry = require('legacy-events/EventPluginRegistry');
6567
React = require('react');
6668
ReactDOM = require('react-dom');
6769
ReactDOMComponentTree = require('../client/ReactDOMComponentTree');
68-
listenToEvent = require('../events/DOMLegacyEventPluginSystem')
69-
.legacyListenToEvent;
70+
if (ReactFeatureFlags.enableModernEventSystem) {
71+
listenToEvent = require('../events/DOMModernPluginEventSystem')
72+
.listenToEvent;
73+
} else {
74+
listenToEvent = require('../events/DOMLegacyEventPluginSystem')
75+
.legacyListenToEvent;
76+
}
77+
7078
ReactDOMEventListener = require('../events/ReactDOMEventListener');
7179
ReactTestUtils = require('react-dom/test-utils');
7280

packages/react-dom/src/__tests__/ReactDOMEventListener-test.js

Lines changed: 64 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -12,36 +12,41 @@
1212
describe('ReactDOMEventListener', () => {
1313
let React;
1414
let ReactDOM;
15+
let ReactFeatureFlags = require('shared/ReactFeatureFlags');
1516

1617
beforeEach(() => {
1718
jest.resetModules();
1819
React = require('react');
1920
ReactDOM = require('react-dom');
2021
});
2122

22-
it('should dispatch events from outside React tree', () => {
23-
const mock = jest.fn();
23+
// We attached events to roots with the modern system,
24+
// so this test is no longer valid.
25+
if (!ReactFeatureFlags.enableModernEventSystem) {
26+
it('should dispatch events from outside React tree', () => {
27+
const mock = jest.fn();
2428

25-
const container = document.createElement('div');
26-
const node = ReactDOM.render(<div onMouseEnter={mock} />, container);
27-
const otherNode = document.createElement('h1');
28-
document.body.appendChild(container);
29-
document.body.appendChild(otherNode);
29+
const container = document.createElement('div');
30+
const node = ReactDOM.render(<div onMouseEnter={mock} />, container);
31+
const otherNode = document.createElement('h1');
32+
document.body.appendChild(container);
33+
document.body.appendChild(otherNode);
3034

31-
try {
32-
otherNode.dispatchEvent(
33-
new MouseEvent('mouseout', {
34-
bubbles: true,
35-
cancelable: true,
36-
relatedTarget: node,
37-
}),
38-
);
39-
expect(mock).toBeCalled();
40-
} finally {
41-
document.body.removeChild(container);
42-
document.body.removeChild(otherNode);
43-
}
44-
});
35+
try {
36+
otherNode.dispatchEvent(
37+
new MouseEvent('mouseout', {
38+
bubbles: true,
39+
cancelable: true,
40+
relatedTarget: node,
41+
}),
42+
);
43+
expect(mock).toBeCalled();
44+
} finally {
45+
document.body.removeChild(container);
46+
document.body.removeChild(otherNode);
47+
}
48+
});
49+
}
4550

4651
describe('Propagation', () => {
4752
it('should propagate events one level down', () => {
@@ -189,9 +194,25 @@ describe('ReactDOMEventListener', () => {
189194
// The first call schedules a render of '1' into the 'Child'.
190195
// However, we're batching so it isn't flushed yet.
191196
expect(mock.mock.calls[0][0]).toBe('Child');
192-
// The first call schedules a render of '2' into the 'Child'.
193-
// We're still batching so it isn't flushed yet either.
194-
expect(mock.mock.calls[1][0]).toBe('Child');
197+
if (ReactFeatureFlags.enableModernEventSystem) {
198+
// As we have two roots, it means we have two event listeners.
199+
// This also means we enter the event batching phase twice,
200+
// flushing the child to be 1.
201+
202+
// We don't have any good way of knowing if another event will
203+
// occur because another event handler might invoke
204+
// stopPropagation() along the way. After discussions internally
205+
// with Sebastian, it seems that for now over-flushing should
206+
// be fine, especially as the new event system is a breaking
207+
// change anyway. We can maybe revisit this later as part of
208+
// the work to refine this in the scheduler (maybe by leveraging
209+
// isInputPending?).
210+
expect(mock.mock.calls[1][0]).toBe('1');
211+
} else {
212+
// The first call schedules a render of '2' into the 'Child'.
213+
// We're still batching so it isn't flushed yet either.
214+
expect(mock.mock.calls[1][0]).toBe('Child');
215+
}
195216
// By the time we leave the handler, the second update is flushed.
196217
expect(childNode.textContent).toBe('2');
197218
} finally {
@@ -362,13 +383,25 @@ describe('ReactDOMEventListener', () => {
362383
bubbles: false,
363384
}),
364385
);
365-
// Historically, we happened to not support onLoadStart
366-
// on <img>, and this test documents that lack of support.
367-
// If we decide to support it in the future, we should change
368-
// this line to expect 1 call. Note that fixing this would
369-
// be simple but would require attaching a handler to each
370-
// <img>. So far nobody asked us for it.
371-
expect(handleImgLoadStart).toHaveBeenCalledTimes(0);
386+
if (ReactFeatureFlags.enableModernEventSystem) {
387+
// As of the modern event system refactor, we now support
388+
// this on <img>. The reason for this, is because we now
389+
// attach all media events to the "root" or "portal" in the
390+
// capture phase, rather than the bubble phase. This allows
391+
// us to assign less event listeners to individual elements,
392+
// which also nicely allows us to support more without needing
393+
// to add more individual code paths to support various
394+
// events that do not bubble.
395+
expect(handleImgLoadStart).toHaveBeenCalledTimes(1);
396+
} else {
397+
// Historically, we happened to not support onLoadStart
398+
// on <img>, and this test documents that lack of support.
399+
// If we decide to support it in the future, we should change
400+
// this line to expect 1 call. Note that fixing this would
401+
// be simple but would require attaching a handler to each
402+
// <img>. So far nobody asked us for it.
403+
expect(handleImgLoadStart).toHaveBeenCalledTimes(0);
404+
}
372405

373406
videoRef.current.dispatchEvent(
374407
new ProgressEvent('loadstart', {

packages/react-dom/src/__tests__/ReactTreeTraversal-test.js

Lines changed: 84 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
let React;
1313
let ReactDOM;
14+
let ReactFeatureFlags = require('shared/ReactFeatureFlags');
1415

1516
const ChildComponent = ({id, eventHandler}) => (
1617
<div
@@ -203,41 +204,89 @@ describe('ReactTreeTraversal', () => {
203204
expect(mockFn.mock.calls).toEqual(expectedCalls);
204205
});
205206

206-
it('should enter from the window', () => {
207-
const enterNode = document.getElementById('P_P1_C1__DIV');
208-
209-
const expectedCalls = [
210-
['P', 'mouseenter'],
211-
['P_P1', 'mouseenter'],
212-
['P_P1_C1__DIV', 'mouseenter'],
213-
];
214-
215-
outerNode1.dispatchEvent(
216-
new MouseEvent('mouseout', {
217-
bubbles: true,
218-
cancelable: true,
219-
relatedTarget: enterNode,
220-
}),
221-
);
222-
223-
expect(mockFn.mock.calls).toEqual(expectedCalls);
224-
});
225-
226-
it('should enter from the window to the shallowest', () => {
227-
const enterNode = document.getElementById('P');
228-
229-
const expectedCalls = [['P', 'mouseenter']];
230-
231-
outerNode1.dispatchEvent(
232-
new MouseEvent('mouseout', {
233-
bubbles: true,
234-
cancelable: true,
235-
relatedTarget: enterNode,
236-
}),
237-
);
238-
239-
expect(mockFn.mock.calls).toEqual(expectedCalls);
240-
});
207+
// This will not work with the modern event system that
208+
// attaches event listeners to roots as the event below
209+
// is being triggered on a node that React does not listen
210+
// to any more. Instead we should fire mouseover.
211+
if (ReactFeatureFlags.enableModernEventSystem) {
212+
it('should enter from the window', () => {
213+
const enterNode = document.getElementById('P_P1_C1__DIV');
214+
215+
const expectedCalls = [
216+
['P', 'mouseenter'],
217+
['P_P1', 'mouseenter'],
218+
['P_P1_C1__DIV', 'mouseenter'],
219+
];
220+
221+
enterNode.dispatchEvent(
222+
new MouseEvent('mouseover', {
223+
bubbles: true,
224+
cancelable: true,
225+
relatedTarget: outerNode1,
226+
}),
227+
);
228+
229+
expect(mockFn.mock.calls).toEqual(expectedCalls);
230+
});
231+
} else {
232+
it('should enter from the window', () => {
233+
const enterNode = document.getElementById('P_P1_C1__DIV');
234+
235+
const expectedCalls = [
236+
['P', 'mouseenter'],
237+
['P_P1', 'mouseenter'],
238+
['P_P1_C1__DIV', 'mouseenter'],
239+
];
240+
241+
outerNode1.dispatchEvent(
242+
new MouseEvent('mouseout', {
243+
bubbles: true,
244+
cancelable: true,
245+
relatedTarget: enterNode,
246+
}),
247+
);
248+
249+
expect(mockFn.mock.calls).toEqual(expectedCalls);
250+
});
251+
}
252+
253+
// This will not work with the modern event system that
254+
// attaches event listeners to roots as the event below
255+
// is being triggered on a node that React does not listen
256+
// to any more. Instead we should fire mouseover.
257+
if (ReactFeatureFlags.enableModernEventSystem) {
258+
it('should enter from the window to the shallowest', () => {
259+
const enterNode = document.getElementById('P');
260+
261+
const expectedCalls = [['P', 'mouseenter']];
262+
263+
enterNode.dispatchEvent(
264+
new MouseEvent('mouseover', {
265+
bubbles: true,
266+
cancelable: true,
267+
relatedTarget: outerNode1,
268+
}),
269+
);
270+
271+
expect(mockFn.mock.calls).toEqual(expectedCalls);
272+
});
273+
} else {
274+
it('should enter from the window to the shallowest', () => {
275+
const enterNode = document.getElementById('P');
276+
277+
const expectedCalls = [['P', 'mouseenter']];
278+
279+
outerNode1.dispatchEvent(
280+
new MouseEvent('mouseout', {
281+
bubbles: true,
282+
cancelable: true,
283+
relatedTarget: enterNode,
284+
}),
285+
);
286+
287+
expect(mockFn.mock.calls).toEqual(expectedCalls);
288+
});
289+
}
241290

242291
it('should leave to the window', () => {
243292
const leaveNode = document.getElementById('P_P1_C1__DIV');

0 commit comments

Comments
 (0)