Skip to content

Commit 1757db6

Browse files
committed
Merge branch 'master' of github.com:facebook/react into unacted-effects-warn
2 parents 2a6974e + de7a09c commit 1757db6

16 files changed

+1099
-1177
lines changed

.circleci/config.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -204,10 +204,8 @@ jobs:
204204
- run:
205205
name: Run fuzz tests
206206
command: |
207-
FUZZ_TEST_SEED=$RANDOM
208-
echo $FUZZ_TEST_SEED
209-
yarn test fuzz --maxWorkers=2
210-
yarn test-prod fuzz --maxWorkers=2
207+
FUZZ_TEST_SEED=$RANDOM yarn test fuzz --maxWorkers=2
208+
FUZZ_TEST_SEED=$RANDOM yarn test-prod fuzz --maxWorkers=2
211209
212210
test_build_prod:
213211
docker: *docker

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

Lines changed: 0 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
'use strict';
1111

1212
const React = require('react');
13-
const Fragment = React.Fragment;
1413
let ReactFeatureFlags = require('shared/ReactFeatureFlags');
1514

1615
let ReactDOM;
@@ -602,84 +601,4 @@ describe('ReactDOMFiberAsync', () => {
602601
expect(root.createBatch).toBe(undefined);
603602
});
604603
});
605-
606-
describe('Disable yielding', () => {
607-
beforeEach(() => {
608-
jest.resetModules();
609-
ReactFeatureFlags = require('shared/ReactFeatureFlags');
610-
ReactFeatureFlags.disableYielding = true;
611-
ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false;
612-
ReactDOM = require('react-dom');
613-
Scheduler = require('scheduler');
614-
});
615-
616-
it('wont yield during a render if yielding is disabled', () => {
617-
class A extends React.Component {
618-
render() {
619-
Scheduler.yieldValue('A');
620-
return <div>{this.props.children}</div>;
621-
}
622-
}
623-
624-
class B extends React.Component {
625-
render() {
626-
Scheduler.yieldValue('B');
627-
return <div>{this.props.children}</div>;
628-
}
629-
}
630-
631-
class C extends React.Component {
632-
render() {
633-
Scheduler.yieldValue('C');
634-
return <div>{this.props.children}</div>;
635-
}
636-
}
637-
638-
let root = ReactDOM.unstable_createRoot(container);
639-
640-
root.render(
641-
<Fragment>
642-
<A />
643-
<B />
644-
<C />
645-
</Fragment>,
646-
);
647-
648-
expect(Scheduler).toHaveYielded([]);
649-
650-
Scheduler.unstable_flushNumberOfYields(2);
651-
// Even though we just flushed two yields, we should have rendered
652-
// everything without yielding when the flag is on.
653-
expect(Scheduler).toHaveYielded(['A', 'B', 'C']);
654-
});
655-
656-
it('wont suspend during a render if yielding is disabled', () => {
657-
let p = new Promise(resolve => {});
658-
659-
function Suspend() {
660-
throw p;
661-
}
662-
663-
let root = ReactDOM.unstable_createRoot(container);
664-
root.render(
665-
<React.Suspense fallback={'Loading'}>Initial</React.Suspense>,
666-
);
667-
668-
Scheduler.flushAll();
669-
expect(container.textContent).toBe('Initial');
670-
671-
root.render(
672-
<React.Suspense fallback={'Loading'}>
673-
<Suspend />
674-
</React.Suspense>,
675-
);
676-
677-
expect(Scheduler).toHaveYielded([]);
678-
679-
Scheduler.flushAll();
680-
681-
// This should have flushed to the DOM even though we haven't ran the timers.
682-
expect(container.textContent).toBe('Loading');
683-
});
684-
});
685604
});

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

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -83,25 +83,25 @@ describe('ReactDOMSuspensePlaceholder', () => {
8383
<div ref={divs[1]}>
8484
<AsyncText ms={500} text="B" />
8585
</div>
86-
<div style={{display: 'block'}} ref={divs[2]}>
86+
<div style={{display: 'inline'}} ref={divs[2]}>
8787
<Text text="C" />
8888
</div>
8989
</Suspense>
9090
);
9191
}
9292
ReactDOM.render(<App />, container);
93-
expect(divs[0].current.style.display).toEqual('none !important');
94-
expect(divs[1].current.style.display).toEqual('none !important');
95-
expect(divs[2].current.style.display).toEqual('none !important');
93+
expect(window.getComputedStyle(divs[0].current).display).toEqual('none');
94+
expect(window.getComputedStyle(divs[1].current).display).toEqual('none');
95+
expect(window.getComputedStyle(divs[2].current).display).toEqual('none');
9696

9797
await advanceTimers(500);
9898

9999
Scheduler.flushAll();
100100

101-
expect(divs[0].current.style.display).toEqual('');
102-
expect(divs[1].current.style.display).toEqual('');
101+
expect(window.getComputedStyle(divs[0].current).display).toEqual('block');
102+
expect(window.getComputedStyle(divs[1].current).display).toEqual('block');
103103
// This div's display was set with a prop.
104-
expect(divs[2].current.style.display).toEqual('block');
104+
expect(window.getComputedStyle(divs[2].current).display).toEqual('inline');
105105
});
106106

107107
it('hides and unhides timed out text nodes', async () => {
@@ -156,14 +156,14 @@ describe('ReactDOMSuspensePlaceholder', () => {
156156
ReactDOM.render(<App />, container);
157157
});
158158
expect(container.innerHTML).toEqual(
159-
'<span style="display: none !important;">Sibling</span><span style=' +
160-
'"display: none !important;"></span>Loading...',
159+
'<span style="display: none;">Sibling</span><span style=' +
160+
'"display: none;"></span>Loading...',
161161
);
162162

163163
act(() => setIsVisible(true));
164164
expect(container.innerHTML).toEqual(
165-
'<span style="display: none !important;">Sibling</span><span style=' +
166-
'"display: none !important;"></span>Loading...',
165+
'<span style="display: none;">Sibling</span><span style=' +
166+
'"display: none;"></span>Loading...',
167167
);
168168

169169
await advanceTimers(500);

packages/react-dom/src/client/ReactDOMHostConfig.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,12 @@ export function hideInstance(instance: Instance): void {
589589
// TODO: Does this work for all element types? What about MathML? Should we
590590
// pass host context to this method?
591591
instance = ((instance: any): HTMLElement);
592-
instance.style.display = 'none !important';
592+
const style = instance.style;
593+
if (typeof style.setProperty === 'function') {
594+
style.setProperty('display', 'none', 'important');
595+
} else {
596+
style.display = 'none';
597+
}
593598
}
594599

595600
export function hideTextInstance(textInstance: TextInstance): void {

packages/react-fresh/src/ReactFreshBabelPlugin.js

Lines changed: 63 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -163,36 +163,6 @@ export default function(babel) {
163163
return false;
164164
}
165165

166-
let hookCalls = new WeakMap();
167-
168-
function recordHookCall(functionNode, hookCallPath, hookName) {
169-
if (!hookCalls.has(functionNode)) {
170-
hookCalls.set(functionNode, []);
171-
}
172-
let hookCallsForFn = hookCalls.get(functionNode);
173-
let key = '';
174-
if (hookCallPath.parent.type === 'VariableDeclarator') {
175-
// TODO: if there is no LHS, consider some other heuristic.
176-
key = hookCallPath.parentPath.get('id').getSource();
177-
}
178-
179-
// Some built-in Hooks reset on edits to arguments.
180-
const args = hookCallPath.get('arguments');
181-
if (hookName === 'useState' && args.length > 0) {
182-
// useState second argument is initial state.
183-
key += '(' + args[0].getSource() + ')';
184-
} else if (hookName === 'useReducer' && args.length > 1) {
185-
// useReducer second argument is initial state.
186-
key += '(' + args[1].getSource() + ')';
187-
}
188-
189-
hookCallsForFn.push({
190-
name: hookName,
191-
callee: hookCallPath.node.callee,
192-
key,
193-
});
194-
}
195-
196166
function isBuiltinHook(hookName) {
197167
switch (hookName) {
198168
case 'useState':
@@ -299,9 +269,64 @@ export default function(babel) {
299269

300270
let seenForRegistration = new WeakSet();
301271
let seenForSignature = new WeakSet();
302-
let seenForHookCalls = new WeakSet();
303272
let seenForOutro = new WeakSet();
304273

274+
let hookCalls = new WeakMap();
275+
const HookCallsVisitor = {
276+
CallExpression(path) {
277+
const node = path.node;
278+
const callee = node.callee;
279+
280+
// Note: this visitor MUST NOT mutate the tree in any way.
281+
// It runs early in a separate traversal and should be very fast.
282+
283+
let name = null;
284+
switch (callee.type) {
285+
case 'Identifier':
286+
name = callee.name;
287+
break;
288+
case 'MemberExpression':
289+
name = callee.property.name;
290+
break;
291+
}
292+
if (name === null || !/^use[A-Z]/.test(name)) {
293+
return;
294+
}
295+
const fnScope = path.scope.getFunctionParent();
296+
if (fnScope === null) {
297+
return;
298+
}
299+
300+
// This is a Hook call. Record it.
301+
const fnNode = fnScope.block;
302+
if (!hookCalls.has(fnNode)) {
303+
hookCalls.set(fnNode, []);
304+
}
305+
let hookCallsForFn = hookCalls.get(fnNode);
306+
let key = '';
307+
if (path.parent.type === 'VariableDeclarator') {
308+
// TODO: if there is no LHS, consider some other heuristic.
309+
key = path.parentPath.get('id').getSource();
310+
}
311+
312+
// Some built-in Hooks reset on edits to arguments.
313+
const args = path.get('arguments');
314+
if (name === 'useState' && args.length > 0) {
315+
// useState second argument is initial state.
316+
key += '(' + args[0].getSource() + ')';
317+
} else if (name === 'useReducer' && args.length > 1) {
318+
// useReducer second argument is initial state.
319+
key += '(' + args[1].getSource() + ')';
320+
}
321+
322+
hookCallsForFn.push({
323+
callee: path.node.callee,
324+
name,
325+
key,
326+
});
327+
},
328+
};
329+
305330
return {
306331
visitor: {
307332
ExportDefaultDeclaration(path) {
@@ -617,38 +642,14 @@ export default function(babel) {
617642
},
618643
);
619644
},
620-
CallExpression(path) {
621-
const node = path.node;
622-
const callee = node.callee;
623-
624-
let name = null;
625-
switch (callee.type) {
626-
case 'Identifier':
627-
name = callee.name;
628-
break;
629-
case 'MemberExpression':
630-
name = callee.property.name;
631-
break;
632-
}
633-
if (name === null || !/^use[A-Z]/.test(name)) {
634-
return;
635-
}
636-
637-
// Make sure we're not recording the same calls twice.
638-
// This can happen if another Babel plugin replaces parents.
639-
if (seenForHookCalls.has(node)) {
640-
return;
641-
}
642-
seenForHookCalls.add(node);
643-
// Don't mutate the tree above this point.
644-
645-
const fn = path.scope.getFunctionParent();
646-
if (fn === null) {
647-
return;
648-
}
649-
recordHookCall(fn.block, path, name);
650-
},
651645
Program: {
646+
enter(path) {
647+
// This is a separate early visitor because we need to collect Hook calls
648+
// and "const [foo, setFoo] = ..." signatures before the destructuring
649+
// transform mangles them. This extra traversal is not ideal for perf,
650+
// but it's the best we can do until we stop transpiling destructuring.
651+
path.traverse(HookCallsVisitor);
652+
},
652653
exit(path) {
653654
const registrations = registrationsByProgramPath.get(path);
654655
if (registrations === undefined) {

packages/react-fresh/src/__tests__/ReactFresh-test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,7 +1361,7 @@ describe('ReactFresh', () => {
13611361
const fallbackChild = container.childNodes[1];
13621362
expect(primaryChild.textContent).toBe('Content 1');
13631363
expect(primaryChild.style.color).toBe('green');
1364-
expect(primaryChild.style.display).toBe('none !important');
1364+
expect(primaryChild.style.display).toBe('none');
13651365
expect(fallbackChild.textContent).toBe('Fallback 0');
13661366
expect(fallbackChild.style.color).toBe('green');
13671367
expect(fallbackChild.style.display).toBe('');
@@ -1375,7 +1375,7 @@ describe('ReactFresh', () => {
13751375
expect(container.childNodes[1]).toBe(fallbackChild);
13761376
expect(primaryChild.textContent).toBe('Content 1');
13771377
expect(primaryChild.style.color).toBe('green');
1378-
expect(primaryChild.style.display).toBe('none !important');
1378+
expect(primaryChild.style.display).toBe('none');
13791379
expect(fallbackChild.textContent).toBe('Fallback 1');
13801380
expect(fallbackChild.style.color).toBe('green');
13811381
expect(fallbackChild.style.display).toBe('');
@@ -1399,7 +1399,7 @@ describe('ReactFresh', () => {
13991399
expect(container.childNodes[1]).toBe(fallbackChild);
14001400
expect(primaryChild.textContent).toBe('Content 1');
14011401
expect(primaryChild.style.color).toBe('red');
1402-
expect(primaryChild.style.display).toBe('none !important');
1402+
expect(primaryChild.style.display).toBe('none');
14031403
expect(fallbackChild.textContent).toBe('Fallback 1');
14041404
expect(fallbackChild.style.color).toBe('red');
14051405
expect(fallbackChild.style.display).toBe('');

0 commit comments

Comments
 (0)