@samitouri / QOS-React / commits / b979db4e72

Bump Prettier (#17811)

* Bump Prettier * Reformat * Use non-deprecated option

Dan Abramov committed Jan 9, 2020 at 13:54 UTC b979db4e7215957f03c4221622f0b115a868439a
158 files changed +2341 -2392
.prettierrc.js
+1 -1
@@ -8,7 +8,7 @@ module.exports = {
8 jsxBracketSameLine: true,
9 trailingComma: 'es5',
10 printWidth: 80,
11 - parser: 'babylon',
11 + parser: 'babel',
12
13 overrides: [
14 {
fixtures/attribute-behavior/src/App.js
+5 -9
@@ -461,9 +461,7 @@ function prepareState(initGlobals) {
461 hasSameBehaviorForAll,
462 rowPatternHash,
463 // "Good enough" id that we can store in localStorage
464 - rowIdHash: `${attribute.name} ${attribute.tagName} ${
465 - attribute.overrideStringValue
466 - }`,
464 + rowIdHash: `${attribute.name} ${attribute.tagName} ${attribute.overrideStringValue}`,
465 };
466 const rowGroup = rowPatternHashes.get(rowPatternHash) || new Set();
467 rowGroup.add(row);
@@ -866,14 +864,12 @@ class App extends React.Component {
864 // Sort
865 switch (sortOrder) {
866 case ALPHABETICAL:
869 - return filteredAttributes.sort(
870 - (attr1, attr2) =>
871 - attr1.name.toLowerCase() < attr2.name.toLowerCase() ? -1 : 1
867 + return filteredAttributes.sort((attr1, attr2) =>
868 + attr1.name.toLowerCase() < attr2.name.toLowerCase() ? -1 : 1
869 );
870 case REV_ALPHABETICAL:
874 - return filteredAttributes.sort(
875 - (attr1, attr2) =>
876 - attr1.name.toLowerCase() < attr2.name.toLowerCase() ? 1 : -1
871 + return filteredAttributes.sort((attr1, attr2) =>
872 + attr1.name.toLowerCase() < attr2.name.toLowerCase() ? 1 : -1
873 );
874 case GROUPED_BY_ROW_PATTERN: {
875 return filteredAttributes.sort((attr1, attr2) => {
fixtures/dom/src/components/Iframe.js
+1 -1
@@ -55,4 +55,4 @@ class IframeSubtree extends React.Component {
55 }
56 }
57
58 -export default (ReactDOM.createPortal ? IframePortal : IframeSubtree);
58 +export default ReactDOM.createPortal ? IframePortal : IframeSubtree;
fixtures/dom/src/components/fixtures/home.js
+2 -1
@@ -33,7 +33,8 @@ export default function Home() {
33 <td>
34 <a href="https://www.mozilla.org/en-US/firefox/organizations/">
35 ESR<sup>†</sup>
36 - </a>, Latest
36 + </a>
37 + , Latest
38 </td>
39 </tr>
40 <tr>
fixtures/dom/src/components/fixtures/suspense/index.js
+5 -3
@@ -213,8 +213,8 @@ class TextInputFixtures extends React.Component {
213
214 <Fixture>
215 <SuspendyTree>
216 - <img src="https://upload.wikimedia.org/wikipedia/commons/e/ee/Atom_%282%29.png" />React
217 - is cool
216 + <img src="https://upload.wikimedia.org/wikipedia/commons/e/ee/Atom_%282%29.png" />
217 + React is cool
218 </SuspendyTree>
219 </Fixture>
220 </TestCase>
@@ -308,7 +308,9 @@ class TextInputFixtures extends React.Component {
308 <div style={{height: 200, overflow: 'scroll'}}>
309 {Array(20)
310 .fill()
311 - .map((_, i) => <h2 key={i}>{i + 1}</h2>)}
311 + .map((_, i) => (
312 + <h2 key={i}>{i + 1}</h2>
313 + ))}
314 </div>
315 </SuspendyTree>
316 </Fixture>
fixtures/dom/src/toWarnDev.js
+1 -3
@@ -205,9 +205,7 @@ const createMatcherFor = consoleMethod =>
205 if (withoutStack !== warningsWithoutComponentStack.length) {
206 return {
207 message: () =>
208 - `Expected ${withoutStack} warnings without a component stack but received ${
209 - warningsWithoutComponentStack.length
210 - }:\n` +
208 + `Expected ${withoutStack} warnings without a component stack but received ${warningsWithoutComponentStack.length}:\n` +
209 warningsWithoutComponentStack.map(warning =>
210 this.utils.printReceived(warning)
211 ),
fixtures/eslint/index.js
+15 -18
@@ -8,22 +8,19 @@ function Comment({comment, commentSource}) {
8 const currentUserID = comment.viewer.id;
9 const environment = RelayEnvironment.forUser(currentUserID);
10 const commentID = nullthrows(comment.id);
11 - useEffect(
12 - () => {
13 - const subscription = SubscriptionCounter.subscribeOnce(
14 - `StoreSubscription_${commentID}`,
15 - () =>
16 - StoreSubscription.subscribe(
17 - environment,
18 - {
19 - comment_id: commentID,
20 - },
21 - currentUserID,
22 - commentSource
23 - )
24 - );
25 - return () => subscription.dispose();
26 - },
27 - [commentID, commentSource, currentUserID, environment]
28 - );
11 + useEffect(() => {
12 + const subscription = SubscriptionCounter.subscribeOnce(
13 + `StoreSubscription_${commentID}`,
14 + () =>
15 + StoreSubscription.subscribe(
16 + environment,
17 + {
18 + comment_id: commentID,
19 + },
20 + currentUserID,
21 + commentSource
22 + )
23 + );
24 + return () => subscription.dispose();
25 + }, [commentID, commentSource, currentUserID, environment]);
26 }
fixtures/fiber-debugger/src/App.js
+1 -2
@@ -192,8 +192,7 @@ class App extends Component {
192 }
193 />
194 <p>
195 - Step {currentStep}
196 - : {friendlyAction} (
195 + Step {currentStep}: {friendlyAction} (
196 <a style={{color: 'gray'}} onClick={this.handleEdit} href="#">
197 Edit
198 </a>
fixtures/fiber-debugger/src/Fibers.js
+70 -77
@@ -330,83 +330,76 @@ export default function Fibers({fibers, show, graphSettings, ...rest}) {
330 ]}
331 </div>
332 </Vertex>,
333 - fiber.child &&
334 - show.child && (
335 - <Edge
336 - source={fiber.id}
337 - target={fiber.child}
338 - kind="child"
339 - weight={1000}
340 - key={`${fiber.id}-${fiber.child}-child`}>
341 - child
342 - </Edge>
343 - ),
344 - fiber.sibling &&
345 - show.sibling && (
346 - <Edge
347 - source={fiber.id}
348 - target={fiber.sibling}
349 - kind="sibling"
350 - weight={2000}
351 - key={`${fiber.id}-${fiber.sibling}-sibling`}>
352 - sibling
353 - </Edge>
354 - ),
355 - fiber.return &&
356 - show.return && (
357 - <Edge
358 - source={fiber.id}
359 - target={fiber.return}
360 - kind="return"
361 - weight={1000}
362 - key={`${fiber.id}-${fiber.return}-return`}>
363 - return
364 - </Edge>
365 - ),
366 - fiber.nextEffect &&
367 - show.fx && (
368 - <Edge
369 - source={fiber.id}
370 - target={fiber.nextEffect}
371 - kind="fx"
372 - weight={100}
373 - key={`${fiber.id}-${fiber.nextEffect}-nextEffect`}>
374 - nextFx
375 - </Edge>
376 - ),
377 - fiber.firstEffect &&
378 - show.fx && (
379 - <Edge
380 - source={fiber.id}
381 - target={fiber.firstEffect}
382 - kind="fx"
383 - weight={100}
384 - key={`${fiber.id}-${fiber.firstEffect}-firstEffect`}>
385 - firstFx
386 - </Edge>
387 - ),
388 - fiber.lastEffect &&
389 - show.fx && (
390 - <Edge
391 - source={fiber.id}
392 - target={fiber.lastEffect}
393 - kind="fx"
394 - weight={100}
395 - key={`${fiber.id}-${fiber.lastEffect}-lastEffect`}>
396 - lastFx
397 - </Edge>
398 - ),
399 - fiber.alternate &&
400 - show.alt && (
401 - <Edge
402 - source={fiber.id}
403 - target={fiber.alternate}
404 - kind="alt"
405 - weight={10}
406 - key={`${fiber.id}-${fiber.alternate}-alt`}>
407 - alt
408 - </Edge>
409 - ),
333 + fiber.child && show.child && (
334 + <Edge
335 + source={fiber.id}
336 + target={fiber.child}
337 + kind="child"
338 + weight={1000}
339 + key={`${fiber.id}-${fiber.child}-child`}>
340 + child
341 + </Edge>
342 + ),
343 + fiber.sibling && show.sibling && (
344 + <Edge
345 + source={fiber.id}
346 + target={fiber.sibling}
347 + kind="sibling"
348 + weight={2000}
349 + key={`${fiber.id}-${fiber.sibling}-sibling`}>
350 + sibling
351 + </Edge>
352 + ),
353 + fiber.return && show.return && (
354 + <Edge
355 + source={fiber.id}
356 + target={fiber.return}
357 + kind="return"
358 + weight={1000}
359 + key={`${fiber.id}-${fiber.return}-return`}>
360 + return
361 + </Edge>
362 + ),
363 + fiber.nextEffect && show.fx && (
364 + <Edge
365 + source={fiber.id}
366 + target={fiber.nextEffect}
367 + kind="fx"
368 + weight={100}
369 + key={`${fiber.id}-${fiber.nextEffect}-nextEffect`}>
370 + nextFx
371 + </Edge>
372 + ),
373 + fiber.firstEffect && show.fx && (
374 + <Edge
375 + source={fiber.id}
376 + target={fiber.firstEffect}
377 + kind="fx"
378 + weight={100}
379 + key={`${fiber.id}-${fiber.firstEffect}-firstEffect`}>
380 + firstFx
381 + </Edge>
382 + ),
383 + fiber.lastEffect && show.fx && (
384 + <Edge
385 + source={fiber.id}
386 + target={fiber.lastEffect}
387 + kind="fx"
388 + weight={100}
389 + key={`${fiber.id}-${fiber.lastEffect}-lastEffect`}>
390 + lastFx
391 + </Edge>
392 + ),
393 + fiber.alternate && show.alt && (
394 + <Edge
395 + source={fiber.id}
396 + target={fiber.alternate}
397 + kind="alt"
398 + weight={10}
399 + key={`${fiber.id}-${fiber.alternate}-alt`}>
400 + alt
401 + </Edge>
402 + ),
403 ])}
404 </Graph>
405 </div>
package.json
+1 -1
@@ -71,7 +71,7 @@
71 "ncp": "^2.0.0",
72 "object-assign": "^4.1.1",
73 "pacote": "^9.5.6",
74 - "prettier": "1.13.7",
74 + "prettier": "1.19.1",
75 "prop-types": "^15.6.2",
76 "random-seed": "^0.3.0",
77 "react-lifecycles-compat": "^3.0.2",
packages/create-subscription/src/__tests__/createSubscription-test.internal.js
+8 -2
@@ -118,7 +118,10 @@ describe('createSubscription', () => {
118 const Subscription = createSubscription({
119 getCurrentValue: source => undefined,
120 subscribe: (source, callback) => {
121 - source.then(value => callback(value), value => callback(value));
121 + source.then(
122 + value => callback(value),
123 + value => callback(value),
124 + );
125 // (Can't unsubscribe from a Promise)
126 return () => {};
127 },
@@ -196,7 +199,10 @@ describe('createSubscription', () => {
199 const Subscription = createSubscription({
200 getCurrentValue: source => undefined,
201 subscribe: (source, callback) => {
199 - source.then(value => callback(value), value => callback(value));
202 + source.then(
203 + value => callback(value),
204 + value => callback(value),
205 + );
206 // (Can't unsubscribe from a Promise)
207 return () => {};
208 },
packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js
+6 -18
@@ -613,21 +613,15 @@ export default {
613 context.report({
614 node: declaredDependencyNode,
615 message:
616 - `The ${
617 - declaredDependencyNode.raw
618 - } literal is not a valid dependency ` +
616 + `The ${declaredDependencyNode.raw} literal is not a valid dependency ` +
617 `because it never changes. ` +
620 - `Did you mean to include ${
621 - declaredDependencyNode.value
622 - } in the array instead?`,
618 + `Did you mean to include ${declaredDependencyNode.value} in the array instead?`,
619 });
620 } else {
621 context.report({
622 node: declaredDependencyNode,
623 message:
628 - `The ${
629 - declaredDependencyNode.raw
630 - } literal is not a valid dependency ` +
624 + `The ${declaredDependencyNode.raw} literal is not a valid dependency ` +
625 'because it never changes. You can safely remove it.',
626 });
627 }
@@ -697,22 +691,16 @@ export default {
691 bareFunctions.forEach(({fn, suggestUseCallback}) => {
692 let message =
693 `The '${fn.name.name}' function makes the dependencies of ` +
700 - `${reactiveHookName} Hook (at line ${
701 - declaredDependenciesNode.loc.start.line
702 - }) ` +
694 + `${reactiveHookName} Hook (at line ${declaredDependenciesNode.loc.start.line}) ` +
695 `change on every render.`;
696 if (suggestUseCallback) {
697 message +=
698 ` To fix this, ` +
707 - `wrap the '${
708 - fn.name.name
709 - }' definition into its own useCallback() Hook.`;
699 + `wrap the '${fn.name.name}' definition into its own useCallback() Hook.`;
700 } else {
701 message +=
702 ` Move it inside the ${reactiveHookName} callback. ` +
713 - `Alternatively, wrap the '${
714 - fn.name.name
715 - }' definition into its own useCallback() Hook.`;
703 + `Alternatively, wrap the '${fn.name.name}' definition into its own useCallback() Hook.`;
704 }
705 // TODO: What if the function needs to change on every render anyway?
706 // Should we suggest removing effect deps as an appropriate fix too?
packages/legacy-events/EventPluginUtils.js
+4 -4
@@ -40,15 +40,15 @@ if (__DEV__) {
40 const listenersLen = listenersIsArr
41 ? dispatchListeners.length
42 : dispatchListeners
43 - ? 1
44 - : 0;
43 + ? 1
44 + : 0;
45
46 const instancesIsArr = Array.isArray(dispatchInstances);
47 const instancesLen = instancesIsArr
48 ? dispatchInstances.length
49 : dispatchInstances
50 - ? 1
51 - : 0;
50 + ? 1
51 + : 0;
52
53 if (instancesIsArr !== listenersIsArr || instancesLen !== listenersLen) {
54 console.error('EventPluginUtils: Invalid `event`.');
packages/legacy-events/ReactGenericBatching.js
+2 -1
@@ -119,7 +119,8 @@ export function flushDiscreteUpdatesIfNeeded(timeStamp: number) {
119 if (
120 !isInsideEventHandler &&
121 (!enableDeprecatedFlareAPI ||
122 - (timeStamp === 0 || lastFlushedEventTimeStamp !== timeStamp))
122 + timeStamp === 0 ||
123 + lastFlushedEventTimeStamp !== timeStamp)
124 ) {
125 lastFlushedEventTimeStamp = timeStamp;
126 flushDiscreteUpdatesImpl();
packages/legacy-events/ResponderEventPlugin.js
+10 -10
@@ -350,10 +350,10 @@ function setResponderAndExtractTransfer(
350 const shouldSetEventType = isStartish(topLevelType)
351 ? eventTypes.startShouldSetResponder
352 : isMoveish(topLevelType)
353 - ? eventTypes.moveShouldSetResponder
354 - : topLevelType === TOP_SELECTION_CHANGE
355 - ? eventTypes.selectionChangeShouldSetResponder
356 - : eventTypes.scrollShouldSetResponder;
353 + ? eventTypes.moveShouldSetResponder
354 + : topLevelType === TOP_SELECTION_CHANGE
355 + ? eventTypes.selectionChangeShouldSetResponder
356 + : eventTypes.scrollShouldSetResponder;
357
358 // TODO: stop one short of the current responder.
359 const bubbleShouldSetFrom = !responderInst
@@ -550,10 +550,10 @@ const ResponderEventPlugin = {
550 const incrementalTouch = isResponderTouchStart
551 ? eventTypes.responderStart
552 : isResponderTouchMove
553 - ? eventTypes.responderMove
554 - : isResponderTouchEnd
555 - ? eventTypes.responderEnd
556 - : null;
553 + ? eventTypes.responderMove
554 + : isResponderTouchEnd
555 + ? eventTypes.responderEnd
556 + : null;
557
558 if (incrementalTouch) {
559 const gesture = ResponderSyntheticEvent.getPooled(
@@ -577,8 +577,8 @@ const ResponderEventPlugin = {
577 const finalTouch = isResponderTerminate
578 ? eventTypes.responderTerminate
579 : isResponderRelease
580 - ? eventTypes.responderRelease
581 - : null;
580 + ? eventTypes.responderRelease
581 + : null;
582 if (finalTouch) {
583 const finalEvent = ResponderSyntheticEvent.getPooled(
584 finalTouch,
packages/legacy-events/__tests__/ResponderEventPlugin-test.internal.js
+6 -6
@@ -79,12 +79,12 @@ const _touchConfig = function(
79 topType === 'topTouchStart'
80 ? allTouchObjects
81 : topType === 'topTouchMove'
82 - ? allTouchObjects
83 - : topType === 'topTouchEnd'
84 - ? antiSubsequence(allTouchObjects, changedIndices)
85 - : topType === 'topTouchCancel'
86 - ? antiSubsequence(allTouchObjects, changedIndices)
87 - : null;
82 + ? allTouchObjects
83 + : topType === 'topTouchEnd'
84 + ? antiSubsequence(allTouchObjects, changedIndices)
85 + : topType === 'topTouchCancel'
86 + ? antiSubsequence(allTouchObjects, changedIndices)
87 + : null;
88
89 return {
90 nativeEvent: touchEvent(
packages/react-art/src/__tests__/ReactART-test.js
+3 -1
@@ -214,7 +214,9 @@ describe('ReactART', () => {
214 const chars = this.props.chars.split('');
215 return (
216 <Surface>
217 - {chars.map(text => <Shape key={text} title={text} />)}
217 + {chars.map(text => (
218 + <Shape key={text} title={text} />
219 + ))}
220 </Surface>
221 );
222 }
packages/react-cache/src/__tests__/ReactCache-test.internal.js
+66 -56
@@ -33,46 +33,53 @@ describe('ReactCache', () => {
33 ReactTestRenderer = require('react-test-renderer');
34 Scheduler = require('scheduler');
35
36 - TextResource = createResource(([text, ms = 0]) => {
37 - let listeners = null;
38 - let status = 'pending';
39 - let value = null;
40 - return {
41 - then(resolve, reject) {
42 - switch (status) {
43 - case 'pending': {
44 - if (listeners === null) {
45 - listeners = [{resolve, reject}];
46 - setTimeout(() => {
47 - if (textResourceShouldFail) {
48 - Scheduler.unstable_yieldValue(`Promise rejected [${text}]`);
49 - status = 'rejected';
50 - value = new Error('Failed to load: ' + text);
51 - listeners.forEach(listener => listener.reject(value));
52 - } else {
53 - Scheduler.unstable_yieldValue(`Promise resolved [${text}]`);
54 - status = 'resolved';
55 - value = text;
56 - listeners.forEach(listener => listener.resolve(value));
57 - }
58 - }, ms);
59 - } else {
60 - listeners.push({resolve, reject});
36 + TextResource = createResource(
37 + ([text, ms = 0]) => {
38 + let listeners = null;
39 + let status = 'pending';
40 + let value = null;
41 + return {
42 + then(resolve, reject) {
43 + switch (status) {
44 + case 'pending': {
45 + if (listeners === null) {
46 + listeners = [{resolve, reject}];
47 + setTimeout(() => {
48 + if (textResourceShouldFail) {
49 + Scheduler.unstable_yieldValue(
50 + `Promise rejected [${text}]`,
51 + );
52 + status = 'rejected';
53 + value = new Error('Failed to load: ' + text);
54 + listeners.forEach(listener => listener.reject(value));
55 + } else {
56 + Scheduler.unstable_yieldValue(
57 + `Promise resolved [${text}]`,
58 + );
59 + status = 'resolved';
60 + value = text;
61 + listeners.forEach(listener => listener.resolve(value));
62 + }
63 + }, ms);
64 + } else {
65 + listeners.push({resolve, reject});
66 + }
67 + break;
68 + }
69 + case 'resolved': {
70 + resolve(value);
71 + break;
72 + }
73 + case 'rejected': {
74 + reject(value);
75 + break;
76 }
62 - break;
63 - }
64 - case 'resolved': {
65 - resolve(value);
66 - break;
67 - }
68 - case 'rejected': {
69 - reject(value);
70 - break;
77 }
72 - }
73 - },
74 - };
75 - }, ([text, ms]) => text);
78 + },
79 + };
80 + },
81 + ([text, ms]) => text,
82 + );
83
84 textResourceShouldFail = false;
85 });
@@ -293,26 +300,29 @@ describe('ReactCache', () => {
300
301 it('if a thenable resolves multiple times, does not update the first cached value', () => {
302 let resolveThenable;
296 - const BadTextResource = createResource(([text, ms = 0]) => {
297 - let listeners = null;
298 - let value = null;
299 - return {
300 - then(resolve, reject) {
301 - if (value !== null) {
302 - resolve(value);
303 - } else {
304 - if (listeners === null) {
305 - listeners = [resolve];
306 - resolveThenable = v => {
307 - listeners.forEach(listener => listener(v));
308 - };
303 + const BadTextResource = createResource(
304 + ([text, ms = 0]) => {
305 + let listeners = null;
306 + let value = null;
307 + return {
308 + then(resolve, reject) {
309 + if (value !== null) {
310 + resolve(value);
311 } else {
310 - listeners.push(resolve);
312 + if (listeners === null) {
313 + listeners = [resolve];
314 + resolveThenable = v => {
315 + listeners.forEach(listener => listener(v));
316 + };
317 + } else {
318 + listeners.push(resolve);
319 + }
320 }
312 - }
313 - },
314 - };
315 - }, ([text, ms]) => text);
321 + },
322 + };
323 + },
324 + ([text, ms]) => text,
325 + );
326
327 function BadAsyncText(props) {
328 const text = props.text;
packages/react-debug-tools/src/ReactDebugHooks.js
+2 -2
@@ -116,8 +116,8 @@ function useState<S>(
116 hook !== null
117 ? hook.memoizedState
118 : typeof initialState === 'function'
119 - ? initialState()
120 - : initialState;
119 + ? initialState()
120 + : initialState;
121 hookLog.push({primitive: 'State', stackError: new Error(), value: state});
122 return [state, (action: BasicStateAction<S>) => {}];
123 }
packages/react-devtools-core/src/backend.js
+2 -5
@@ -33,9 +33,7 @@ installHook(window);
33
34 const hook: DevToolsHook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__;
35
36 -let savedComponentFilters: Array<
37 - ComponentFilter,
38 -> = getDefaultComponentFilters();
36 +let savedComponentFilters: Array<ComponentFilter> = getDefaultComponentFilters();
37
38 function debug(methodName: string, ...args) {
39 if (__DEBUG__) {
@@ -56,8 +54,7 @@ export function connectToDevTools(options: ?ConnectOptions) {
54 websocket,
55 resolveRNStyle = null,
56 isAppActive = () => true,
59 - } =
60 - options || {};
57 + } = options || {};
58
59 let retryTimeoutID: TimeoutID | null = null;
60
packages/react-devtools-shared/src/__tests__/inspectedElementContext-test.js
+8 -2
@@ -520,9 +520,15 @@ describe('InspectedElementContext', () => {
520 const exampleFunction = () => {};
521 const exampleDateISO = '2019-12-31T23:42:42.000Z';
522 const setShallow = new Set(['abc', 123]);
523 - const mapShallow = new Map([['name', 'Brian'], ['food', 'sushi']]);
523 + const mapShallow = new Map([
524 + ['name', 'Brian'],
525 + ['food', 'sushi'],
526 + ]);
527 const setOfSets = new Set([new Set(['a', 'b', 'c']), new Set([1, 2, 3])]);
525 - const mapOfMaps = new Map([['first', mapShallow], ['second', mapShallow]]);
528 + const mapOfMaps = new Map([
529 + ['first', mapShallow],
530 + ['second', mapShallow],
531 + ]);
532 const objectOfObjects = {
533 inner: {string: 'abc', number: 123, boolean: true},
534 };
packages/react-devtools-shared/src/__tests__/legacy/inspectElement-test.js
+8 -2
@@ -151,9 +151,15 @@ describe('InspectedElementContext', () => {
151 const div = document.createElement('div');
152 const exampleFunction = () => {};
153 const setShallow = new Set(['abc', 123]);
154 - const mapShallow = new Map([['name', 'Brian'], ['food', 'sushi']]);
154 + const mapShallow = new Map([
155 + ['name', 'Brian'],
156 + ['food', 'sushi'],
157 + ]);
158 const setOfSets = new Set([new Set(['a', 'b', 'c']), new Set([1, 2, 3])]);
156 - const mapOfMaps = new Map([['first', mapShallow], ['second', mapShallow]]);
159 + const mapOfMaps = new Map([
160 + ['first', mapShallow],
161 + ['second', mapShallow],
162 + ]);
163 const objectOfObjects = {
164 inner: {string: 'abc', number: 123, boolean: true},
165 };
packages/react-devtools-shared/src/__tests__/legacy/storeLegacy-v15-test.js
+18 -6
@@ -63,7 +63,9 @@ describe('Store (legacy)', () => {
63 );
64 const Parent = ({count}) => (
65 <div>
66 - {new Array(count).fill(true).map((_, index) => <Child key={index} />)}
66 + {new Array(count).fill(true).map((_, index) => (
67 + <Child key={index} />
68 + ))}
69 </div>
70 );
71 const Child = () => <div>Hi!</div>;
@@ -83,7 +85,9 @@ describe('Store (legacy)', () => {
85 it('should support mount and update operations for multiple roots', () => {
86 const Parent = ({count}) => (
87 <div>
86 - {new Array(count).fill(true).map((_, index) => <Child key={index} />)}
88 + {new Array(count).fill(true).map((_, index) => (
89 + <Child key={index} />
90 + ))}
91 </div>
92 );
93 const Child = () => <div>Hi!</div>;
@@ -155,7 +159,9 @@ describe('Store (legacy)', () => {
159 );
160 const Parent = ({count}) => (
161 <div>
158 - {new Array(count).fill(true).map((_, index) => <Child key={index} />)}
162 + {new Array(count).fill(true).map((_, index) => (
163 + <Child key={index} />
164 + ))}
165 </div>
166 );
167 const Child = () => <div>Hi!</div>;
@@ -261,7 +267,9 @@ describe('Store (legacy)', () => {
267 it('should support mount and update operations', () => {
268 const Parent = ({count}) => (
269 <div>
264 - {new Array(count).fill(true).map((_, index) => <Child key={index} />)}
270 + {new Array(count).fill(true).map((_, index) => (
271 + <Child key={index} />
272 + ))}
273 </div>
274 );
275 const Child = () => <div>Hi!</div>;
@@ -297,7 +305,9 @@ describe('Store (legacy)', () => {
305 it('should support mount and update operations for multiple roots', () => {
306 const Parent = ({count}) => (
307 <div>
300 - {new Array(count).fill(true).map((_, index) => <Child key={index} />)}
308 + {new Array(count).fill(true).map((_, index) => (
309 + <Child key={index} />
310 + ))}
311 </div>
312 );
313 const Child = () => <div>Hi!</div>;
@@ -375,7 +385,9 @@ describe('Store (legacy)', () => {
385 );
386 const Parent = ({count}) => (
387 <div>
378 - {new Array(count).fill(true).map((_, index) => <Child key={index} />)}
388 + {new Array(count).fill(true).map((_, index) => (
389 + <Child key={index} />
390 + ))}
391 </div>
392 );
393 const Child = () => <div>Hi!</div>;
packages/react-devtools-shared/src/backend/views/Highlighter/index.js
+3 -3
@@ -103,9 +103,9 @@ export default function setupHighlighter(
103
104 let nodes: ?Array<HTMLElement> = null;
105 if (renderer !== null) {
106 - nodes = ((renderer.findNativeNodesForFiberID(id): any): ?Array<
107 - HTMLElement,
108 - >);
106 + nodes = ((renderer.findNativeNodesForFiberID(
107 + id,
108 + ): any): ?Array<HTMLElement>);
109 }
110
111 if (nodes != null && nodes[0] != null) {
packages/react-devtools-shared/src/devtools/ContextMenu/ContextMenu.js
+34 -40
@@ -74,55 +74,49 @@ export default function ContextMenu({children, id}: Props) {
74 };
75 }, []);
76
77 - useEffect(
78 - () => {
79 - const showMenu = ({data, pageX, pageY}) => {
80 - setState({data, isVisible: true, pageX, pageY});
81 - };
82 - const hideMenu = () => setState(HIDDEN_STATE);
83 - return registerMenu(id, showMenu, hideMenu);
84 - },
85 - [id],
86 - );
87 -
88 - useLayoutEffect(
89 - () => {
90 - if (!state.isVisible) {
91 - return;
92 - }
77 + useEffect(() => {
78 + const showMenu = ({data, pageX, pageY}) => {
79 + setState({data, isVisible: true, pageX, pageY});
80 + };
81 + const hideMenu = () => setState(HIDDEN_STATE);
82 + return registerMenu(id, showMenu, hideMenu);
83 + }, [id]);
84
94 - const menu = menuRef.current;
85 + useLayoutEffect(() => {
86 + if (!state.isVisible) {
87 + return;
88 + }
89
96 - const hideUnlessContains = event => {
97 - if (!menu.contains(event.target)) {
98 - setState(HIDDEN_STATE);
99 - }
100 - };
90 + const menu = menuRef.current;
91
102 - const hide = event => {
92 + const hideUnlessContains = event => {
93 + if (!menu.contains(event.target)) {
94 setState(HIDDEN_STATE);
104 - };
95 + }
96 + };
97
106 - const ownerDocument = containerRef.current.ownerDocument;
107 - ownerDocument.addEventListener('mousedown', hideUnlessContains);
108 - ownerDocument.addEventListener('touchstart', hideUnlessContains);
109 - ownerDocument.addEventListener('keydown', hideUnlessContains);
98 + const hide = event => {
99 + setState(HIDDEN_STATE);
100 + };
101
111 - const ownerWindow = ownerDocument.defaultView;
112 - ownerWindow.addEventListener('resize', hide);
102 + const ownerDocument = containerRef.current.ownerDocument;
103 + ownerDocument.addEventListener('mousedown', hideUnlessContains);
104 + ownerDocument.addEventListener('touchstart', hideUnlessContains);
105 + ownerDocument.addEventListener('keydown', hideUnlessContains);
106
114 - respositionToFit(menu, state.pageX, state.pageY);
107 + const ownerWindow = ownerDocument.defaultView;
108 + ownerWindow.addEventListener('resize', hide);
109
116 - return () => {
117 - ownerDocument.removeEventListener('mousedown', hideUnlessContains);
118 - ownerDocument.removeEventListener('touchstart', hideUnlessContains);
119 - ownerDocument.removeEventListener('keydown', hideUnlessContains);
110 + respositionToFit(menu, state.pageX, state.pageY);
111
121 - ownerWindow.removeEventListener('resize', hide);
122 - };
123 - },
124 - [state],
125 - );
112 + return () => {
113 + ownerDocument.removeEventListener('mousedown', hideUnlessContains);
114 + ownerDocument.removeEventListener('touchstart', hideUnlessContains);
115 + ownerDocument.removeEventListener('keydown', hideUnlessContains);
116 +
117 + ownerWindow.removeEventListener('resize', hide);
118 + };
119 + }, [state]);
120
121 if (!state.isVisible) {
122 return <div ref={bodyAccessorRef} />;
packages/react-devtools-shared/src/devtools/ContextMenu/useContextMenu.js
+20 -25
@@ -23,29 +23,24 @@ export default function useContextMenu({
23 |}) {
24 const {showMenu} = useContext(RegistryContext);
25
26 - useEffect(
27 - () => {
28 - if (ref.current !== null) {
29 - const handleContextMenu = event => {
30 - event.preventDefault();
31 - event.stopPropagation();
32 -
33 - const pageX =
34 - event.pageX || (event.touches && event.touches[0].pageX);
35 - const pageY =
36 - event.pageY || (event.touches && event.touches[0].pageY);
37 -
38 - showMenu({data, id, pageX, pageY});
39 - };
40 -
41 - const trigger = ref.current;
42 - trigger.addEventListener('contextmenu', handleContextMenu);
43 -
44 - return () => {
45 - trigger.removeEventListener('contextmenu', handleContextMenu);
46 - };
47 - }
48 - },
49 - [data, id, showMenu],
50 - );
26 + useEffect(() => {
27 + if (ref.current !== null) {
28 + const handleContextMenu = event => {
29 + event.preventDefault();
30 + event.stopPropagation();
31 +
32 + const pageX = event.pageX || (event.touches && event.touches[0].pageX);
33 + const pageY = event.pageY || (event.touches && event.touches[0].pageY);
34 +
35 + showMenu({data, id, pageX, pageY});
36 + };
37 +
38 + const trigger = ref.current;
39 + trigger.addEventListener('contextmenu', handleContextMenu);
40 +
41 + return () => {
42 + trigger.removeEventListener('contextmenu', handleContextMenu);
43 + };
44 + }
45 + }, [data, id, showMenu]);
46 }
packages/react-devtools-shared/src/devtools/store.js
+1 -3
@@ -364,9 +364,7 @@ export default class Store extends EventEmitter<{|
364 getElementAtIndex(index: number): Element | null {
365 if (index < 0 || index >= this.numElements) {
366 console.warn(
367 - `Invalid index ${index} specified; store contains ${
368 - this.numElements
369 - } items.`,
367 + `Invalid index ${index} specified; store contains ${this.numElements} items.`,
368 );
369
370 return null;
packages/react-devtools-shared/src/devtools/utils.js
+1 -3
@@ -90,9 +90,7 @@ export function printStore(store: Store, includeWeight: boolean = false) {
90 // Make sure the pretty-printed test align with the Store's reported number of total rows.
91 if (rootWeight !== store.numElements) {
92 throw Error(
93 - `Inconsistent Store state. Individual root weights (${rootWeight}) do not match total weight (${
94 - store.numElements
95 - })`,
93 + `Inconsistent Store state. Individual root weights (${rootWeight}) do not match total weight (${store.numElements})`,
94 );
95 }
96
packages/react-devtools-shared/src/devtools/views/Components/Element.js
+3 -6
@@ -193,12 +193,9 @@ type DisplayNameProps = {|
193
194 function DisplayName({displayName, id}: DisplayNameProps) {
195 const {searchIndex, searchResults, searchText} = useContext(TreeStateContext);
196 - const isSearchResult = useMemo(
197 - () => {
198 - return searchResults.includes(id);
199 - },
200 - [id, searchResults],
201 - );
196 + const isSearchResult = useMemo(() => {
197 + return searchResults.includes(id);
198 + }, [id, searchResults]);
199 const isCurrentResult =
200 searchIndex !== null && id === searchResults[searchIndex];
201
packages/react-devtools-shared/src/devtools/views/Components/InspectHostNodesToggle.js
+6 -9
@@ -29,15 +29,12 @@ export default function InspectHostNodesToggle() {
29 [bridge],
30 );
31
32 - useEffect(
33 - () => {
34 - const onStopInspectingNative = () => setIsInspecting(false);
35 - bridge.addListener('stopInspectingNative', onStopInspectingNative);
36 - return () =>
37 - bridge.removeListener('stopInspectingNative', onStopInspectingNative);
38 - },
39 - [bridge],
40 - );
32 + useEffect(() => {
33 + const onStopInspectingNative = () => setIsInspecting(false);
34 + bridge.addListener('stopInspectingNative', onStopInspectingNative);
35 + return () =>
36 + bridge.removeListener('stopInspectingNative', onStopInspectingNative);
37 + }, [bridge]);
38
39 return (
40 <Toggle
packages/react-devtools-shared/src/devtools/views/Components/InspectedElementContext.js
+141 -148
@@ -162,169 +162,162 @@ function InspectedElementContextController({children}: Props) {
162 ] = useState<InspectedElementFrontend | null>(null);
163
164 // This effect handler invalidates the suspense cache and schedules rendering updates with React.
165 - useEffect(
166 - () => {
167 - const onInspectedElement = (data: InspectedElementPayload) => {
168 - const {id} = data;
169 -
170 - let element;
171 -
172 - switch (data.type) {
173 - case 'no-change':
174 - case 'not-found':
175 - // No-op
176 - break;
177 - case 'hydrated-path':
178 - // Merge new data into previous object and invalidate cache
179 - element = store.getElementByID(id);
180 - if (element !== null) {
181 - if (currentlyInspectedElement != null) {
182 - const value = hydrateHelper(data.value, data.path);
183 - const inspectedElement = {...currentlyInspectedElement};
184 -
185 - fillInPath(inspectedElement, data.value, data.path, value);
186 -
187 - resource.write(element, inspectedElement);
188 -
189 - // Schedule update with React if the curently-selected element has been invalidated.
190 - if (id === selectedElementID) {
191 - setCurrentlyInspectedElement(inspectedElement);
192 - }
165 + useEffect(() => {
166 + const onInspectedElement = (data: InspectedElementPayload) => {
167 + const {id} = data;
168 +
169 + let element;
170 +
171 + switch (data.type) {
172 + case 'no-change':
173 + case 'not-found':
174 + // No-op
175 + break;
176 + case 'hydrated-path':
177 + // Merge new data into previous object and invalidate cache
178 + element = store.getElementByID(id);
179 + if (element !== null) {
180 + if (currentlyInspectedElement != null) {
181 + const value = hydrateHelper(data.value, data.path);
182 + const inspectedElement = {...currentlyInspectedElement};
183 +
184 + fillInPath(inspectedElement, data.value, data.path, value);
185 +
186 + resource.write(element, inspectedElement);
187 +
188 + // Schedule update with React if the curently-selected element has been invalidated.
189 + if (id === selectedElementID) {
190 + setCurrentlyInspectedElement(inspectedElement);
191 }
192 }
195 - break;
196 - case 'full-data':
197 - const {
198 - canEditFunctionProps,
199 - canEditHooks,
200 - canToggleSuspense,
201 - canViewSource,
202 - hasLegacyContext,
203 - source,
204 - type,
205 - owners,
206 - context,
207 - hooks,
208 - props,
209 - state,
210 - } = ((data.value: any): InspectedElementBackend);
211 -
212 - const inspectedElement: InspectedElementFrontend = {
213 - canEditFunctionProps,
214 - canEditHooks,
215 - canToggleSuspense,
216 - canViewSource,
217 - hasLegacyContext,
218 - id,
219 - source,
220 - type,
221 - owners:
222 - owners === null
223 - ? null
224 - : owners.map(owner => {
225 - const [
226 - displayName,
227 - hocDisplayNames,
228 - ] = separateDisplayNameAndHOCs(
229 - owner.displayName,
230 - owner.type,
231 - );
232 - return {
233 - ...owner,
234 - displayName,
235 - hocDisplayNames,
236 - };
237 - }),
238 - context: hydrateHelper(context),
239 - hooks: hydrateHelper(hooks),
240 - props: hydrateHelper(props),
241 - state: hydrateHelper(state),
242 - };
243 -
244 - element = store.getElementByID(id);
245 - if (element !== null) {
246 - const request = inProgressRequests.get(element);
247 - if (request != null) {
248 - inProgressRequests.delete(element);
249 - batchedUpdates(() => {
250 - request.resolveFn(inspectedElement);
251 - setCurrentlyInspectedElement(inspectedElement);
252 - });
253 - } else {
254 - resource.write(element, inspectedElement);
255 -
256 - // Schedule update with React if the curently-selected element has been invalidated.
257 - if (id === selectedElementID) {
258 - setCurrentlyInspectedElement(inspectedElement);
259 - }
193 + }
194 + break;
195 + case 'full-data':
196 + const {
197 + canEditFunctionProps,
198 + canEditHooks,
199 + canToggleSuspense,
200 + canViewSource,
201 + hasLegacyContext,
202 + source,
203 + type,
204 + owners,
205 + context,
206 + hooks,
207 + props,
208 + state,
209 + } = ((data.value: any): InspectedElementBackend);
210 +
211 + const inspectedElement: InspectedElementFrontend = {
212 + canEditFunctionProps,
213 + canEditHooks,
214 + canToggleSuspense,
215 + canViewSource,
216 + hasLegacyContext,
217 + id,
218 + source,
219 + type,
220 + owners:
221 + owners === null
222 + ? null
223 + : owners.map(owner => {
224 + const [
225 + displayName,
226 + hocDisplayNames,
227 + ] = separateDisplayNameAndHOCs(
228 + owner.displayName,
229 + owner.type,
230 + );
231 + return {
232 + ...owner,
233 + displayName,
234 + hocDisplayNames,
235 + };
236 + }),
237 + context: hydrateHelper(context),
238 + hooks: hydrateHelper(hooks),
239 + props: hydrateHelper(props),
240 + state: hydrateHelper(state),
241 + };
242 +
243 + element = store.getElementByID(id);
244 + if (element !== null) {
245 + const request = inProgressRequests.get(element);
246 + if (request != null) {
247 + inProgressRequests.delete(element);
248 + batchedUpdates(() => {
249 + request.resolveFn(inspectedElement);
250 + setCurrentlyInspectedElement(inspectedElement);
251 + });
252 + } else {
253 + resource.write(element, inspectedElement);
254 +
255 + // Schedule update with React if the curently-selected element has been invalidated.
256 + if (id === selectedElementID) {
257 + setCurrentlyInspectedElement(inspectedElement);
258 }
259 }
262 - break;
263 - default:
264 - break;
265 - }
266 - };
260 + }
261 + break;
262 + default:
263 + break;
264 + }
265 + };
266
268 - bridge.addListener('inspectedElement', onInspectedElement);
269 - return () =>
270 - bridge.removeListener('inspectedElement', onInspectedElement);
271 - },
272 - [bridge, currentlyInspectedElement, selectedElementID, store],
273 - );
267 + bridge.addListener('inspectedElement', onInspectedElement);
268 + return () => bridge.removeListener('inspectedElement', onInspectedElement);
269 + }, [bridge, currentlyInspectedElement, selectedElementID, store]);
270
271 // This effect handler polls for updates on the currently selected element.
276 - useEffect(
277 - () => {
278 - if (selectedElementID === null) {
279 - return () => {};
280 - }
272 + useEffect(() => {
273 + if (selectedElementID === null) {
274 + return () => {};
275 + }
276
282 - const rendererID = store.getRendererIDForElement(selectedElementID);
277 + const rendererID = store.getRendererIDForElement(selectedElementID);
278
284 - let timeoutID: TimeoutID | null = null;
279 + let timeoutID: TimeoutID | null = null;
280
286 - const sendRequest = () => {
287 - timeoutID = null;
281 + const sendRequest = () => {
282 + timeoutID = null;
283
289 - if (rendererID !== null) {
290 - bridge.send('inspectElement', {id: selectedElementID, rendererID});
291 - }
292 - };
293 -
294 - // Send the initial inspection request.
295 - // We'll poll for an update in the response handler below.
296 - sendRequest();
297 -
298 - const onInspectedElement = (data: InspectedElementPayload) => {
299 - // If this is the element we requested, wait a little bit and then ask for another update.
300 - if (data.id === selectedElementID) {
301 - switch (data.type) {
302 - case 'no-change':
303 - case 'full-data':
304 - case 'hydrated-path':
305 - if (timeoutID !== null) {
306 - clearTimeout(timeoutID);
307 - }
308 - timeoutID = setTimeout(sendRequest, 1000);
309 - break;
310 - default:
311 - break;
312 - }
284 + if (rendererID !== null) {
285 + bridge.send('inspectElement', {id: selectedElementID, rendererID});
286 + }
287 + };
288 +
289 + // Send the initial inspection request.
290 + // We'll poll for an update in the response handler below.
291 + sendRequest();
292 +
293 + const onInspectedElement = (data: InspectedElementPayload) => {
294 + // If this is the element we requested, wait a little bit and then ask for another update.
295 + if (data.id === selectedElementID) {
296 + switch (data.type) {
297 + case 'no-change':
298 + case 'full-data':
299 + case 'hydrated-path':
300 + if (timeoutID !== null) {
301 + clearTimeout(timeoutID);
302 + }
303 + timeoutID = setTimeout(sendRequest, 1000);
304 + break;
305 + default:
306 + break;
307 }
314 - };
308 + }
309 + };
310
316 - bridge.addListener('inspectedElement', onInspectedElement);
311 + bridge.addListener('inspectedElement', onInspectedElement);
312
318 - return () => {
319 - bridge.removeListener('inspectedElement', onInspectedElement);
313 + return () => {
314 + bridge.removeListener('inspectedElement', onInspectedElement);
315
321 - if (timeoutID !== null) {
322 - clearTimeout(timeoutID);
323 - }
324 - };
325 - },
326 - [bridge, selectedElementID, store],
327 - );
316 + if (timeoutID !== null) {
317 + clearTimeout(timeoutID);
318 + }
319 + };
320 + }, [bridge, selectedElementID, store]);
321
322 const value = useMemo(
323 () => ({
packages/react-devtools-shared/src/devtools/views/Components/KeyValue.js
+11 -14
@@ -55,20 +55,17 @@ export default function KeyValue({
55 value[meta.inspectable] &&
56 value[meta.size] !== 0;
57
58 - useEffect(
59 - () => {
60 - if (
61 - isInspectable &&
62 - isOpen &&
63 - !prevIsOpenRef.current &&
64 - typeof inspectPath === 'function'
65 - ) {
66 - inspectPath(path);
67 - }
68 - prevIsOpenRef.current = isOpen;
69 - },
70 - [inspectPath, isInspectable, isOpen, path],
71 - );
58 + useEffect(() => {
59 + if (
60 + isInspectable &&
61 + isOpen &&
62 + !prevIsOpenRef.current &&
63 + typeof inspectPath === 'function'
64 + ) {
65 + inspectPath(path);
66 + }
67 + prevIsOpenRef.current = isOpen;
68 + }, [inspectPath, isInspectable, isOpen, path]);
69
70 const toggleIsOpen = () => setIsOpen(prevIsOpen => !prevIsOpen);
71
packages/react-devtools-shared/src/devtools/views/Components/NativeStyleEditor/AutoSizeInput.js
+15 -18
@@ -65,27 +65,24 @@ export default function AutoSizeInput({
65 }, []);
66
67 // Resize input any time text changes
68 - useLayoutEffect(
69 - () => {
70 - if (hiddenDivRef.current === null) {
71 - return;
72 - }
68 + useLayoutEffect(() => {
69 + if (hiddenDivRef.current === null) {
70 + return;
71 + }
72
74 - const scrollWidth = hiddenDivRef.current.getBoundingClientRect().width;
75 - if (!scrollWidth) {
76 - return;
77 - }
73 + const scrollWidth = hiddenDivRef.current.getBoundingClientRect().width;
74 + if (!scrollWidth) {
75 + return;
76 + }
77
79 - // Adding an extra pixel avoids a slight horizontal scroll when changing text selection/cursor.
80 - // Not sure why this is, but the old DevTools did a similar thing.
81 - const targetWidth = Math.ceil(scrollWidth) + 1;
78 + // Adding an extra pixel avoids a slight horizontal scroll when changing text selection/cursor.
79 + // Not sure why this is, but the old DevTools did a similar thing.
80 + const targetWidth = Math.ceil(scrollWidth) + 1;
81
83 - if (inputRef.current !== null) {
84 - inputRef.current.style.width = `${targetWidth}px`;
85 - }
86 - },
87 - [value],
88 - );
82 + if (inputRef.current !== null) {
83 + inputRef.current.style.width = `${targetWidth}px`;
84 + }
85 + }, [value]);
86
87 const isEmpty = value === '' || value === '""';
88
packages/react-devtools-shared/src/devtools/views/Components/NativeStyleEditor/context.js
+68 -74
@@ -102,94 +102,88 @@ function NativeStyleContextController({children}: Props) {
102 ] = useState<StyleAndLayoutFrontend | null>(null);
103
104 // This effect handler invalidates the suspense cache and schedules rendering updates with React.
105 - useEffect(
106 - () => {
107 - const onStyleAndLayout = ({id, layout, style}: StyleAndLayoutBackend) => {
108 - let element = store.getElementByID(id);
109 - if (element !== null) {
110 - const styleAndLayout: StyleAndLayoutFrontend = {
111 - layout,
112 - style,
113 - };
114 - const request = inProgressRequests.get(element);
115 - if (request != null) {
116 - inProgressRequests.delete(element);
117 - batchedUpdates(() => {
118 - request.resolveFn(styleAndLayout);
119 - setCurrentStyleAndLayout(styleAndLayout);
120 - });
121 - } else {
122 - resource.write(element, styleAndLayout);
123 -
124 - // Schedule update with React if the currently-selected element has been invalidated.
125 - if (id === selectedElementID) {
126 - setCurrentStyleAndLayout(styleAndLayout);
127 - }
105 + useEffect(() => {
106 + const onStyleAndLayout = ({id, layout, style}: StyleAndLayoutBackend) => {
107 + let element = store.getElementByID(id);
108 + if (element !== null) {
109 + const styleAndLayout: StyleAndLayoutFrontend = {
110 + layout,
111 + style,
112 + };
113 + const request = inProgressRequests.get(element);
114 + if (request != null) {
115 + inProgressRequests.delete(element);
116 + batchedUpdates(() => {
117 + request.resolveFn(styleAndLayout);
118 + setCurrentStyleAndLayout(styleAndLayout);
119 + });
120 + } else {
121 + resource.write(element, styleAndLayout);
122 +
123 + // Schedule update with React if the currently-selected element has been invalidated.
124 + if (id === selectedElementID) {
125 + setCurrentStyleAndLayout(styleAndLayout);
126 }
127 }
130 - };
131 -
132 - bridge.addListener('NativeStyleEditor_styleAndLayout', onStyleAndLayout);
133 - return () =>
134 - bridge.removeListener(
135 - 'NativeStyleEditor_styleAndLayout',
136 - onStyleAndLayout,
137 - );
138 - },
139 - [bridge, currentStyleAndLayout, selectedElementID, store],
140 - );
141 -
142 - // This effect handler polls for updates on the currently selected element.
143 - useEffect(
144 - () => {
145 - if (selectedElementID === null) {
146 - return () => {};
128 }
129 + };
130
149 - const rendererID = store.getRendererIDForElement(selectedElementID);
150 -
151 - let timeoutID: TimeoutID | null = null;
131 + bridge.addListener('NativeStyleEditor_styleAndLayout', onStyleAndLayout);
132 + return () =>
133 + bridge.removeListener(
134 + 'NativeStyleEditor_styleAndLayout',
135 + onStyleAndLayout,
136 + );
137 + }, [bridge, currentStyleAndLayout, selectedElementID, store]);
138
153 - const sendRequest = () => {
154 - timeoutID = null;
139 + // This effect handler polls for updates on the currently selected element.
140 + useEffect(() => {
141 + if (selectedElementID === null) {
142 + return () => {};
143 + }
144
156 - if (rendererID !== null) {
157 - bridge.send('NativeStyleEditor_measure', {
158 - id: selectedElementID,
159 - rendererID,
160 - });
161 - }
162 - };
145 + const rendererID = store.getRendererIDForElement(selectedElementID);
146
164 - // Send the initial measurement request.
165 - // We'll poll for an update in the response handler below.
166 - sendRequest();
147 + let timeoutID: TimeoutID | null = null;
148
168 - const onStyleAndLayout = ({id}: StyleAndLayoutBackend) => {
169 - // If this is the element we requested, wait a little bit and then ask for another update.
170 - if (id === selectedElementID) {
171 - if (timeoutID !== null) {
172 - clearTimeout(timeoutID);
173 - }
174 - timeoutID = setTimeout(sendRequest, 1000);
175 - }
176 - };
149 + const sendRequest = () => {
150 + timeoutID = null;
151
178 - bridge.addListener('NativeStyleEditor_styleAndLayout', onStyleAndLayout);
152 + if (rendererID !== null) {
153 + bridge.send('NativeStyleEditor_measure', {
154 + id: selectedElementID,
155 + rendererID,
156 + });
157 + }
158 + };
159
180 - return () => {
181 - bridge.removeListener(
182 - 'NativeStyleEditor_styleAndLayout',
183 - onStyleAndLayout,
184 - );
160 + // Send the initial measurement request.
161 + // We'll poll for an update in the response handler below.
162 + sendRequest();
163
164 + const onStyleAndLayout = ({id}: StyleAndLayoutBackend) => {
165 + // If this is the element we requested, wait a little bit and then ask for another update.
166 + if (id === selectedElementID) {
167 if (timeoutID !== null) {
168 clearTimeout(timeoutID);
169 }
189 - };
190 - },
191 - [bridge, selectedElementID, store],
192 - );
170 + timeoutID = setTimeout(sendRequest, 1000);
171 + }
172 + };
173 +
174 + bridge.addListener('NativeStyleEditor_styleAndLayout', onStyleAndLayout);
175 +
176 + return () => {
177 + bridge.removeListener(
178 + 'NativeStyleEditor_styleAndLayout',
179 + onStyleAndLayout,
180 + );
181 +
182 + if (timeoutID !== null) {
183 + clearTimeout(timeoutID);
184 + }
185 + };
186 + }, [bridge, selectedElementID, store]);
187
188 const value = useMemo(
189 () => ({getStyleAndLayout}),
packages/react-devtools-shared/src/devtools/views/Components/OwnersListContext.js
+39 -48
@@ -73,60 +73,51 @@ function OwnersListContextController({children}: Props) {
73 [store],
74 );
75
76 - useEffect(
77 - () => {
78 - const onOwnersList = (ownersList: OwnersList) => {
79 - const id = ownersList.id;
80 -
81 - const element = store.getElementByID(id);
82 - if (element !== null) {
83 - const request = inProgressRequests.get(element);
84 - if (request != null) {
85 - inProgressRequests.delete(element);
86 -
87 - request.resolveFn(
88 - ownersList.owners === null
89 - ? null
90 - : ownersList.owners.map(owner => {
91 - const [
92 - displayNameWithoutHOCs,
93 - hocDisplayNames,
94 - ] = separateDisplayNameAndHOCs(
95 - owner.displayName,
96 - owner.type,
97 - );
98 -
99 - return {
100 - ...owner,
101 - displayName: displayNameWithoutHOCs,
102 - hocDisplayNames,
103 - };
104 - }),
105 - );
106 - }
76 + useEffect(() => {
77 + const onOwnersList = (ownersList: OwnersList) => {
78 + const id = ownersList.id;
79 +
80 + const element = store.getElementByID(id);
81 + if (element !== null) {
82 + const request = inProgressRequests.get(element);
83 + if (request != null) {
84 + inProgressRequests.delete(element);
85 +
86 + request.resolveFn(
87 + ownersList.owners === null
88 + ? null
89 + : ownersList.owners.map(owner => {
90 + const [
91 + displayNameWithoutHOCs,
92 + hocDisplayNames,
93 + ] = separateDisplayNameAndHOCs(owner.displayName, owner.type);
94 +
95 + return {
96 + ...owner,
97 + displayName: displayNameWithoutHOCs,
98 + hocDisplayNames,
99 + };
100 + }),
101 + );
102 }
108 - };
103 + }
104 + };
105
110 - bridge.addListener('ownersList', onOwnersList);
111 - return () => bridge.removeListener('ownersList', onOwnersList);
112 - },
113 - [bridge, store],
114 - );
106 + bridge.addListener('ownersList', onOwnersList);
107 + return () => bridge.removeListener('ownersList', onOwnersList);
108 + }, [bridge, store]);
109
110 // This effect requests an updated owners list any time the selected owner changes
117 - useEffect(
118 - () => {
119 - if (ownerID !== null) {
120 - const rendererID = store.getRendererIDForElement(ownerID);
121 - if (rendererID !== null) {
122 - bridge.send('getOwnersList', {id: ownerID, rendererID});
123 - }
111 + useEffect(() => {
112 + if (ownerID !== null) {
113 + const rendererID = store.getRendererIDForElement(ownerID);
114 + if (rendererID !== null) {
115 + bridge.send('getOwnersList', {id: ownerID, rendererID});
116 }
117 + }
118
126 - return () => {};
127 - },
128 - [bridge, ownerID, store],
129 - );
119 + return () => {};
120 + }, [bridge, ownerID, store]);
121
122 return (
123 <OwnersListContext.Provider value={read}>
packages/react-devtools-shared/src/devtools/views/Components/OwnersStack.js
+26 -32
@@ -128,30 +128,27 @@ export default function OwnerStack() {
128
129 const selectedOwner = owners[selectedIndex];
130
131 - useLayoutEffect(
132 - () => {
133 - // If we're already overflowing, then we don't need to re-measure items.
134 - // That's because once the owners stack is open, it can only get larger (by driling in).
135 - // A totally new stack can only be reached by exiting this mode and re-entering it.
136 - if (elementsBarRef.current === null || isOverflowing) {
137 - return () => {};
138 - }
139 -
140 - let totalWidth = 0;
141 - for (let i = 0; i < owners.length; i++) {
142 - const element = elementsBarRef.current.children[i];
143 - const computedStyle = getComputedStyle(element);
144 -
145 - totalWidth +=
146 - element.offsetWidth +
147 - parseInt(computedStyle.marginLeft, 10) +
148 - parseInt(computedStyle.marginRight, 10);
149 - }
150 -
151 - setElementsTotalWidth(totalWidth);
152 - },
153 - [elementsBarRef, isOverflowing, owners.length],
154 - );
131 + useLayoutEffect(() => {
132 + // If we're already overflowing, then we don't need to re-measure items.
133 + // That's because once the owners stack is open, it can only get larger (by driling in).
134 + // A totally new stack can only be reached by exiting this mode and re-entering it.
135 + if (elementsBarRef.current === null || isOverflowing) {
136 + return () => {};
137 + }
138 +
139 + let totalWidth = 0;
140 + for (let i = 0; i < owners.length; i++) {
141 + const element = elementsBarRef.current.children[i];
142 + const computedStyle = getComputedStyle(element);
143 +
144 + totalWidth +=
145 + element.offsetWidth +
146 + parseInt(computedStyle.marginLeft, 10) +
147 + parseInt(computedStyle.marginRight, 10);
148 + }
149 +
150 + setElementsTotalWidth(totalWidth);
151 + }, [elementsBarRef, isOverflowing, owners.length]);
152
153 return (
154 <div className={styles.OwnerStack}>
@@ -255,14 +252,11 @@ function ElementView({isSelected, owner, selectOwner}: ElementViewProps) {
252 const {displayName, hocDisplayNames, type} = owner;
253 const isInStore = store.containsElement(owner.id);
254
258 - const handleChange = useCallback(
259 - () => {
260 - if (isInStore) {
261 - selectOwner(owner);
262 - }
263 - },
264 - [isInStore, selectOwner, owner],
265 - );
255 + const handleChange = useCallback(() => {
256 + if (isInStore) {
257 + selectOwner(owner);
258 + }
259 + }, [isInStore, selectOwner, owner]);
260
261 return (
262 <Toggle
packages/react-devtools-shared/src/devtools/views/Components/SearchInput.js
+20 -24
@@ -66,34 +66,30 @@ export default function SearchInput(props: Props) {
66 );
67
68 // Auto-focus search input
69 - useEffect(
70 - () => {
71 - if (inputRef.current === null) {
72 - return () => {};
73 - }
69 + useEffect(() => {
70 + if (inputRef.current === null) {
71 + return () => {};
72 + }
73
75 - const handleWindowKey = (event: KeyboardEvent) => {
76 - const {key, metaKey} = event;
77 - if (key === 'f' && metaKey) {
78 - if (inputRef.current !== null) {
79 - inputRef.current.focus();
80 - event.preventDefault();
81 - event.stopPropagation();
82 - }
74 + const handleWindowKey = (event: KeyboardEvent) => {
75 + const {key, metaKey} = event;
76 + if (key === 'f' && metaKey) {
77 + if (inputRef.current !== null) {
78 + inputRef.current.focus();
79 + event.preventDefault();
80 + event.stopPropagation();
81 }
84 - };
82 + }
83 + };
84
86 - // It's important to listen to the ownerDocument to support the browser extension.
87 - // Here we use portals to render individual tabs (e.g. Profiler),
88 - // and the root document might belong to a different window.
89 - const ownerDocument = inputRef.current.ownerDocument;
90 - ownerDocument.addEventListener('keydown', handleWindowKey);
85 + // It's important to listen to the ownerDocument to support the browser extension.
86 + // Here we use portals to render individual tabs (e.g. Profiler),
87 + // and the root document might belong to a different window.
88 + const ownerDocument = inputRef.current.ownerDocument;
89 + ownerDocument.addEventListener('keydown', handleWindowKey);
90
92 - return () =>
93 - ownerDocument.removeEventListener('keydown', handleWindowKey);
94 - },
95 - [inputRef],
96 - );
91 + return () => ownerDocument.removeEventListener('keydown', handleWindowKey);
92 + }, [inputRef]);
93
94 return (
95 <div className={styles.SearchInput}>
packages/react-devtools-shared/src/devtools/views/Components/SelectedElement.js
+91 -105
@@ -72,51 +72,42 @@ export default function SelectedElement(_: Props) {
72 const inspectedElement =
73 inspectedElementID != null ? getInspectedElement(inspectedElementID) : null;
74
75 - const highlightElement = useCallback(
76 - () => {
77 - if (element !== null && inspectedElementID !== null) {
78 - const rendererID = store.getRendererIDForElement(inspectedElementID);
79 - if (rendererID !== null) {
80 - bridge.send('highlightNativeElement', {
81 - displayName: element.displayName,
82 - hideAfterTimeout: true,
83 - id: inspectedElementID,
84 - openNativeElementsPanel: true,
85 - rendererID,
86 - scrollIntoView: true,
87 - });
88 - }
89 - }
90 - },
91 - [bridge, element, inspectedElementID, store],
92 - );
93 -
94 - const logElement = useCallback(
95 - () => {
96 - if (inspectedElementID !== null) {
97 - const rendererID = store.getRendererIDForElement(inspectedElementID);
98 - if (rendererID !== null) {
99 - bridge.send('logElementToConsole', {
100 - id: inspectedElementID,
101 - rendererID,
102 - });
103 - }
75 + const highlightElement = useCallback(() => {
76 + if (element !== null && inspectedElementID !== null) {
77 + const rendererID = store.getRendererIDForElement(inspectedElementID);
78 + if (rendererID !== null) {
79 + bridge.send('highlightNativeElement', {
80 + displayName: element.displayName,
81 + hideAfterTimeout: true,
82 + id: inspectedElementID,
83 + openNativeElementsPanel: true,
84 + rendererID,
85 + scrollIntoView: true,
86 + });
87 }
105 - },
106 - [bridge, inspectedElementID, store],
107 - );
88 + }
89 + }, [bridge, element, inspectedElementID, store]);
90
109 - const viewSource = useCallback(
110 - () => {
111 - if (viewElementSourceFunction != null && inspectedElement !== null) {
112 - viewElementSourceFunction(
113 - inspectedElement.id,
114 - ((inspectedElement: any): InspectedElement),
115 - );
91 + const logElement = useCallback(() => {
92 + if (inspectedElementID !== null) {
93 + const rendererID = store.getRendererIDForElement(inspectedElementID);
94 + if (rendererID !== null) {
95 + bridge.send('logElementToConsole', {
96 + id: inspectedElementID,
97 + rendererID,
98 + });
99 }
117 - },
118 - [inspectedElement, viewElementSourceFunction],
119 - );
100 + }
101 + }, [bridge, inspectedElementID, store]);
102 +
103 + const viewSource = useCallback(() => {
104 + if (viewElementSourceFunction != null && inspectedElement !== null) {
105 + viewElementSourceFunction(
106 + inspectedElement.id,
107 + ((inspectedElement: any): InspectedElement),
108 + );
109 + }
110 + }, [inspectedElement, viewElementSourceFunction]);
111
112 // In some cases (e.g. FB internal usage) the standalone shell might not be able to view the source.
113 // To detect this case, we defer to an injected helper function (if present).
@@ -137,56 +128,53 @@ export default function SelectedElement(_: Props) {
128 inspectedElement != null && inspectedElement.canToggleSuspense;
129
130 // TODO (suspense toggle) Would be nice to eventually use a two setState pattern here as well.
140 - const toggleSuspended = useCallback(
141 - () => {
142 - let nearestSuspenseElement = null;
143 - let currentElement = element;
144 - while (currentElement !== null) {
145 - if (currentElement.type === ElementTypeSuspense) {
146 - nearestSuspenseElement = currentElement;
147 - break;
148 - } else if (currentElement.parentID > 0) {
149 - currentElement = store.getElementByID(currentElement.parentID);
150 - } else {
151 - currentElement = null;
152 - }
131 + const toggleSuspended = useCallback(() => {
132 + let nearestSuspenseElement = null;
133 + let currentElement = element;
134 + while (currentElement !== null) {
135 + if (currentElement.type === ElementTypeSuspense) {
136 + nearestSuspenseElement = currentElement;
137 + break;
138 + } else if (currentElement.parentID > 0) {
139 + currentElement = store.getElementByID(currentElement.parentID);
140 + } else {
141 + currentElement = null;
142 }
143 + }
144
155 - // If we didn't find a Suspense ancestor, we can't suspend.
156 - // Instead we can show a warning to the user.
157 - if (nearestSuspenseElement === null) {
158 - modalDialogDispatch({
159 - type: 'SHOW',
160 - content: <CannotSuspendWarningMessage />,
145 + // If we didn't find a Suspense ancestor, we can't suspend.
146 + // Instead we can show a warning to the user.
147 + if (nearestSuspenseElement === null) {
148 + modalDialogDispatch({
149 + type: 'SHOW',
150 + content: <CannotSuspendWarningMessage />,
151 + });
152 + } else {
153 + const nearestSuspenseElementID = nearestSuspenseElement.id;
154 +
155 + // If we're suspending from an arbitary (non-Suspense) component, select the nearest Suspense element in the Tree.
156 + // This way when the fallback UI is shown and the current element is hidden, something meaningful is selected.
157 + if (nearestSuspenseElement !== element) {
158 + dispatch({
159 + type: 'SELECT_ELEMENT_BY_ID',
160 + payload: nearestSuspenseElementID,
161 });
162 - } else {
163 - const nearestSuspenseElementID = nearestSuspenseElement.id;
164 -
165 - // If we're suspending from an arbitary (non-Suspense) component, select the nearest Suspense element in the Tree.
166 - // This way when the fallback UI is shown and the current element is hidden, something meaningful is selected.
167 - if (nearestSuspenseElement !== element) {
168 - dispatch({
169 - type: 'SELECT_ELEMENT_BY_ID',
170 - payload: nearestSuspenseElementID,
171 - });
172 - }
173 -
174 - const rendererID = store.getRendererIDForElement(
175 - nearestSuspenseElementID,
176 - );
177 -
178 - // Toggle suspended
179 - if (rendererID !== null) {
180 - bridge.send('overrideSuspense', {
181 - id: nearestSuspenseElementID,
182 - rendererID,
183 - forceFallback: !isSuspended,
184 - });
185 - }
162 }
187 - },
188 - [bridge, dispatch, element, isSuspended, modalDialogDispatch, store],
189 - );
163 +
164 + const rendererID = store.getRendererIDForElement(
165 + nearestSuspenseElementID,
166 + );
167 +
168 + // Toggle suspended
169 + if (rendererID !== null) {
170 + bridge.send('overrideSuspense', {
171 + id: nearestSuspenseElementID,
172 + rendererID,
173 + forceFallback: !isSuspended,
174 + });
175 + }
176 + }
177 + }, [bridge, dispatch, element, isSuspended, modalDialogDispatch, store]);
178
179 if (element === null) {
180 return (
@@ -417,23 +405,21 @@ function InspectedElementView({
405
406 <NativeStyleEditor />
407
420 - {ownerID === null &&
421 - owners !== null &&
422 - owners.length > 0 && (
423 - <div className={styles.Owners}>
424 - <div className={styles.OwnersHeader}>rendered by</div>
425 - {owners.map(owner => (
426 - <OwnerView
427 - key={owner.id}
428 - displayName={owner.displayName || 'Anonymous'}
429 - hocDisplayNames={owner.hocDisplayNames}
430 - id={owner.id}
431 - isInStore={store.containsElement(owner.id)}
432 - type={owner.type}
433 - />
434 - ))}
435 - </div>
436 - )}
408 + {ownerID === null && owners !== null && owners.length > 0 && (
409 + <div className={styles.Owners}>
410 + <div className={styles.OwnersHeader}>rendered by</div>
411 + {owners.map(owner => (
412 + <OwnerView
413 + key={owner.id}
414 + displayName={owner.displayName || 'Anonymous'}
415 + hocDisplayNames={owner.hocDisplayNames}
416 + id={owner.id}
417 + isInStore={store.containsElement(owner.id)}
418 + type={owner.type}
419 + />
420 + ))}
421 + </div>
422 + )}
423
424 {source !== null && (
425 <Source fileName={source.fileName} lineNumber={source.lineNumber} />
packages/react-devtools-shared/src/devtools/views/Components/Tree.js
+110 -128
@@ -89,22 +89,16 @@ export default function Tree(props: Props) {
89
90 // Picking an element in the inspector should put focus into the tree.
91 // This ensures that keyboard navigation works right after picking a node.
92 - useEffect(
93 - () => {
94 - function handleStopInspectingNative(didSelectNode) {
95 - if (didSelectNode && focusTargetRef.current !== null) {
96 - focusTargetRef.current.focus();
97 - }
92 + useEffect(() => {
93 + function handleStopInspectingNative(didSelectNode) {
94 + if (didSelectNode && focusTargetRef.current !== null) {
95 + focusTargetRef.current.focus();
96 }
99 - bridge.addListener('stopInspectingNative', handleStopInspectingNative);
100 - return () =>
101 - bridge.removeListener(
102 - 'stopInspectingNative',
103 - handleStopInspectingNative,
104 - );
105 - },
106 - [bridge],
107 - );
97 + }
98 + bridge.addListener('stopInspectingNative', handleStopInspectingNative);
99 + return () =>
100 + bridge.removeListener('stopInspectingNative', handleStopInspectingNative);
101 + }, [bridge]);
102
103 // This ref is passed down the context to elements.
104 // It lets them avoid autoscrolling to the same item many times
@@ -112,93 +106,87 @@ export default function Tree(props: Props) {
106 const lastScrolledIDRef = useRef<number | null>(null);
107
108 // Navigate the tree with up/down arrow keys.
115 - useEffect(
116 - () => {
117 - if (treeRef.current === null) {
118 - return () => {};
109 + useEffect(() => {
110 + if (treeRef.current === null) {
111 + return () => {};
112 + }
113 +
114 + const handleKeyDown = (event: KeyboardEvent) => {
115 + if ((event: any).target.tagName === 'INPUT' || event.defaultPrevented) {
116 + return;
117 }
118
121 - const handleKeyDown = (event: KeyboardEvent) => {
122 - if ((event: any).target.tagName === 'INPUT' || event.defaultPrevented) {
123 - return;
124 - }
125 -
126 - // TODO We should ignore arrow keys if the focus is outside of DevTools.
127 - // Otherwise the inline (embedded) DevTools might change selection unexpectedly,
128 - // e.g. when a text input or a select has focus.
129 -
130 - let element;
131 - switch (event.key) {
132 - case 'ArrowDown':
133 - event.preventDefault();
134 - dispatch({type: 'SELECT_NEXT_ELEMENT_IN_TREE'});
135 - break;
136 - case 'ArrowLeft':
137 - event.preventDefault();
138 - element =
139 - selectedElementID !== null
140 - ? store.getElementByID(selectedElementID)
141 - : null;
142 - if (element !== null) {
143 - if (element.children.length > 0 && !element.isCollapsed) {
144 - store.toggleIsCollapsed(element.id, true);
145 - } else {
146 - dispatch({type: 'SELECT_PARENT_ELEMENT_IN_TREE'});
147 - }
119 + // TODO We should ignore arrow keys if the focus is outside of DevTools.
120 + // Otherwise the inline (embedded) DevTools might change selection unexpectedly,
121 + // e.g. when a text input or a select has focus.
122 +
123 + let element;
124 + switch (event.key) {
125 + case 'ArrowDown':
126 + event.preventDefault();
127 + dispatch({type: 'SELECT_NEXT_ELEMENT_IN_TREE'});
128 + break;
129 + case 'ArrowLeft':
130 + event.preventDefault();
131 + element =
132 + selectedElementID !== null
133 + ? store.getElementByID(selectedElementID)
134 + : null;
135 + if (element !== null) {
136 + if (element.children.length > 0 && !element.isCollapsed) {
137 + store.toggleIsCollapsed(element.id, true);
138 + } else {
139 + dispatch({type: 'SELECT_PARENT_ELEMENT_IN_TREE'});
140 }
149 - break;
150 - case 'ArrowRight':
151 - event.preventDefault();
152 - element =
153 - selectedElementID !== null
154 - ? store.getElementByID(selectedElementID)
155 - : null;
156 - if (element !== null) {
157 - if (element.children.length > 0 && element.isCollapsed) {
158 - store.toggleIsCollapsed(element.id, false);
159 - } else {
160 - dispatch({type: 'SELECT_CHILD_ELEMENT_IN_TREE'});
161 - }
141 + }
142 + break;
143 + case 'ArrowRight':
144 + event.preventDefault();
145 + element =
146 + selectedElementID !== null
147 + ? store.getElementByID(selectedElementID)
148 + : null;
149 + if (element !== null) {
150 + if (element.children.length > 0 && element.isCollapsed) {
151 + store.toggleIsCollapsed(element.id, false);
152 + } else {
153 + dispatch({type: 'SELECT_CHILD_ELEMENT_IN_TREE'});
154 }
163 - break;
164 - case 'ArrowUp':
165 - event.preventDefault();
166 - dispatch({type: 'SELECT_PREVIOUS_ELEMENT_IN_TREE'});
167 - break;
168 - default:
169 - return;
170 - }
171 - setIsNavigatingWithKeyboard(true);
172 - };
173 -
174 - // It's important to listen to the ownerDocument to support the browser extension.
175 - // Here we use portals to render individual tabs (e.g. Profiler),
176 - // and the root document might belong to a different window.
177 - const ownerDocument = treeRef.current.ownerDocument;
178 - ownerDocument.addEventListener('keydown', handleKeyDown);
179 -
180 - return () => {
181 - ownerDocument.removeEventListener('keydown', handleKeyDown);
182 - };
183 - },
184 - [dispatch, selectedElementID, store],
185 - );
155 + }
156 + break;
157 + case 'ArrowUp':
158 + event.preventDefault();
159 + dispatch({type: 'SELECT_PREVIOUS_ELEMENT_IN_TREE'});
160 + break;
161 + default:
162 + return;
163 + }
164 + setIsNavigatingWithKeyboard(true);
165 + };
166 +
167 + // It's important to listen to the ownerDocument to support the browser extension.
168 + // Here we use portals to render individual tabs (e.g. Profiler),
169 + // and the root document might belong to a different window.
170 + const ownerDocument = treeRef.current.ownerDocument;
171 + ownerDocument.addEventListener('keydown', handleKeyDown);
172 +
173 + return () => {
174 + ownerDocument.removeEventListener('keydown', handleKeyDown);
175 + };
176 + }, [dispatch, selectedElementID, store]);
177
178 // Focus management.
179 const handleBlur = useCallback(() => setTreeFocused(false), []);
189 - const handleFocus = useCallback(
190 - () => {
191 - setTreeFocused(true);
192 -
193 - if (selectedElementIndex === null && numElements > 0) {
194 - dispatch({
195 - type: 'SELECT_ELEMENT_AT_INDEX',
196 - payload: 0,
197 - });
198 - }
199 - },
200 - [dispatch, numElements, selectedElementIndex],
201 - );
180 + const handleFocus = useCallback(() => {
181 + setTreeFocused(true);
182 +
183 + if (selectedElementIndex === null && numElements > 0) {
184 + dispatch({
185 + type: 'SELECT_ELEMENT_AT_INDEX',
186 + payload: 0,
187 + });
188 + }
189 + }, [dispatch, numElements, selectedElementIndex]);
190
191 const handleKeyPress = useCallback(
192 event => {
@@ -237,34 +225,31 @@ export default function Tree(props: Props) {
225 // If we switch the selected element while using the keyboard,
226 // start highlighting it in the DOM instead of the last hovered node.
227 const searchRef = useRef({searchIndex, searchResults});
240 - useEffect(
241 - () => {
242 - let didSelectNewSearchResult = false;
243 - if (
244 - searchRef.current.searchIndex !== searchIndex ||
245 - searchRef.current.searchResults !== searchResults
246 - ) {
247 - searchRef.current.searchIndex = searchIndex;
248 - searchRef.current.searchResults = searchResults;
249 - didSelectNewSearchResult = true;
250 - }
251 - if (isNavigatingWithKeyboard || didSelectNewSearchResult) {
252 - if (selectedElementID !== null) {
253 - highlightNativeElement(selectedElementID);
254 - } else {
255 - bridge.send('clearNativeElementHighlight');
256 - }
228 + useEffect(() => {
229 + let didSelectNewSearchResult = false;
230 + if (
231 + searchRef.current.searchIndex !== searchIndex ||
232 + searchRef.current.searchResults !== searchResults
233 + ) {
234 + searchRef.current.searchIndex = searchIndex;
235 + searchRef.current.searchResults = searchResults;
236 + didSelectNewSearchResult = true;
237 + }
238 + if (isNavigatingWithKeyboard || didSelectNewSearchResult) {
239 + if (selectedElementID !== null) {
240 + highlightNativeElement(selectedElementID);
241 + } else {
242 + bridge.send('clearNativeElementHighlight');
243 }
258 - },
259 - [
260 - bridge,
261 - isNavigatingWithKeyboard,
262 - highlightNativeElement,
263 - searchIndex,
264 - searchResults,
265 - selectedElementID,
266 - ],
267 - );
244 + }
245 + }, [
246 + bridge,
247 + isNavigatingWithKeyboard,
248 + highlightNativeElement,
249 + searchIndex,
250 + searchResults,
251 + selectedElementID,
252 + ]);
253
254 // Highlight last hovered element.
255 const handleElementMouseEnter = useCallback(
@@ -284,12 +269,9 @@ export default function Tree(props: Props) {
269 setIsNavigatingWithKeyboard(false);
270 }, []);
271
287 - const handleMouseLeave = useCallback(
288 - () => {
289 - bridge.send('clearNativeElementHighlight');
290 - },
291 - [bridge],
292 - );
272 + const handleMouseLeave = useCallback(() => {
273 + bridge.send('clearNativeElementHighlight');
274 + }, [bridge]);
275
276 // Let react-window know to re-render any time the underlying tree data changes.
277 // This includes the owner context, since it controls a filtered view of the tree.
packages/react-devtools-shared/src/devtools/views/Components/TreeContext.js
+40 -49
@@ -718,65 +718,56 @@ function TreeContextController({
718 );
719
720 // Listen for host element selections.
721 - useEffect(
722 - () => {
723 - const handleSelectFiber = (id: number) =>
724 - dispatchWrapper({type: 'SELECT_ELEMENT_BY_ID', payload: id});
725 - bridge.addListener('selectFiber', handleSelectFiber);
726 - return () => bridge.removeListener('selectFiber', handleSelectFiber);
727 - },
728 - [bridge, dispatchWrapper],
729 - );
721 + useEffect(() => {
722 + const handleSelectFiber = (id: number) =>
723 + dispatchWrapper({type: 'SELECT_ELEMENT_BY_ID', payload: id});
724 + bridge.addListener('selectFiber', handleSelectFiber);
725 + return () => bridge.removeListener('selectFiber', handleSelectFiber);
726 + }, [bridge, dispatchWrapper]);
727
728 // If a newly-selected search result or inspection selection is inside of a collapsed subtree, auto expand it.
729 // This needs to be a layout effect to avoid temporarily flashing an incorrect selection.
730 const prevSelectedElementID = useRef<number | null>(null);
734 - useLayoutEffect(
735 - () => {
736 - if (state.selectedElementID !== prevSelectedElementID.current) {
737 - prevSelectedElementID.current = state.selectedElementID;
738 -
739 - if (state.selectedElementID !== null) {
740 - let element = store.getElementByID(state.selectedElementID);
741 - if (element !== null && element.parentID > 0) {
742 - store.toggleIsCollapsed(element.parentID, false);
743 - }
731 + useLayoutEffect(() => {
732 + if (state.selectedElementID !== prevSelectedElementID.current) {
733 + prevSelectedElementID.current = state.selectedElementID;
734 +
735 + if (state.selectedElementID !== null) {
736 + let element = store.getElementByID(state.selectedElementID);
737 + if (element !== null && element.parentID > 0) {
738 + store.toggleIsCollapsed(element.parentID, false);
739 }
740 }
746 - },
747 - [state.selectedElementID, store],
748 - );
741 + }
742 + }, [state.selectedElementID, store]);
743
744 // Mutations to the underlying tree may impact this context (e.g. search results, selection state).
751 - useEffect(
752 - () => {
753 - const handleStoreMutated = ([addedElementIDs, removedElementIDs]: [
754 - Array<number>,
755 - Map<number, number>,
756 - ]) => {
757 - dispatchWrapper({
758 - type: 'HANDLE_STORE_MUTATION',
759 - payload: [addedElementIDs, removedElementIDs],
760 - });
761 - };
762 -
763 - // Since this is a passive effect, the tree may have been mutated before our initial subscription.
764 - if (store.revision !== initialRevision) {
765 - // At the moment, we can treat this as a mutation.
766 - // We don't know which Elements were newly added/removed, but that should be okay in this case.
767 - // It would only impact the search state, which is unlikely to exist yet at this point.
768 - dispatchWrapper({
769 - type: 'HANDLE_STORE_MUTATION',
770 - payload: [[], new Map()],
771 - });
772 - }
745 + useEffect(() => {
746 + const handleStoreMutated = ([addedElementIDs, removedElementIDs]: [
747 + Array<number>,
748 + Map<number, number>,
749 + ]) => {
750 + dispatchWrapper({
751 + type: 'HANDLE_STORE_MUTATION',
752 + payload: [addedElementIDs, removedElementIDs],
753 + });
754 + };
755 +
756 + // Since this is a passive effect, the tree may have been mutated before our initial subscription.
757 + if (store.revision !== initialRevision) {
758 + // At the moment, we can treat this as a mutation.
759 + // We don't know which Elements were newly added/removed, but that should be okay in this case.
760 + // It would only impact the search state, which is unlikely to exist yet at this point.
761 + dispatchWrapper({
762 + type: 'HANDLE_STORE_MUTATION',
763 + payload: [[], new Map()],
764 + });
765 + }
766
774 - store.addListener('mutated', handleStoreMutated);
767 + store.addListener('mutated', handleStoreMutated);
768
776 - return () => store.removeListener('mutated', handleStoreMutated);
777 - },
778 - [dispatchWrapper, initialRevision, store],
779 - );
769 + return () => store.removeListener('mutated', handleStoreMutated);
770 + }, [dispatchWrapper, initialRevision, store]);
771
772 return (
773 <TreeStateContext.Provider value={state}>
packages/react-devtools-shared/src/devtools/views/DevTools.js
+9 -12
@@ -126,18 +126,15 @@ export default function DevTools({
126 [enabledInspectedElementContextMenu, viewAttributeSourceFunction],
127 );
128
129 - useEffect(
130 - () => {
131 - return () => {
132 - try {
133 - bridge.shutdown();
134 - } catch (error) {
135 - // Attempting to use a disconnected port.
136 - }
137 - };
138 - },
139 - [bridge],
140 - );
129 + useEffect(() => {
130 + return () => {
131 + try {
132 + bridge.shutdown();
133 + } catch (error) {
134 + // Attempting to use a disconnected port.
135 + }
136 + };
137 + }, [bridge]);
138
139 return (
140 <BridgeContext.Provider value={bridge}>
packages/react-devtools-shared/src/devtools/views/ModalDialog.js
+5 -8
@@ -111,14 +111,11 @@ function ModalDialogImpl(_: {||}) {
111 const {canBeDismissed, content, dispatch, title} = useContext(
112 ModalDialogContext,
113 );
114 - const dismissModal = useCallback(
115 - () => {
116 - if (canBeDismissed) {
117 - dispatch({type: 'HIDE'});
118 - }
119 - },
120 - [canBeDismissed, dispatch],
121 - );
114 + const dismissModal = useCallback(() => {
115 + if (canBeDismissed) {
116 + dispatch({type: 'HIDE'});
117 + }
118 + }, [canBeDismissed, dispatch]);
119 const dialogRef = useRef<HTMLDivElement | null>(null);
120
121 // It's important to trap click events within the dialog,
packages/react-devtools-shared/src/devtools/views/Profiler/CommitFlamegraph.js
+20 -26
@@ -94,32 +94,26 @@ function CommitFlamegraph({chartData, commitTree, height, width}: Props) {
94 const {lineHeight} = useContext(SettingsContext);
95 const {selectFiber, selectedFiberID} = useContext(ProfilerContext);
96
97 - const selectedChartNodeIndex = useMemo<number>(
98 - () => {
99 - if (selectedFiberID === null) {
100 - return 0;
101 - }
102 - // The selected node might not be in the tree for this commit,
103 - // so it's important that we have a fallback plan.
104 - const depth = chartData.idToDepthMap.get(selectedFiberID);
105 - return depth !== undefined ? depth - 1 : 0;
106 - },
107 - [chartData, selectedFiberID],
108 - );
109 -
110 - const selectedChartNode = useMemo(
111 - () => {
112 - if (selectedFiberID !== null) {
113 - return (
114 - chartData.rows[selectedChartNodeIndex].find(
115 - chartNode => chartNode.id === selectedFiberID,
116 - ) || null
117 - );
118 - }
119 - return null;
120 - },
121 - [chartData, selectedFiberID, selectedChartNodeIndex],
122 - );
97 + const selectedChartNodeIndex = useMemo<number>(() => {
98 + if (selectedFiberID === null) {
99 + return 0;
100 + }
101 + // The selected node might not be in the tree for this commit,
102 + // so it's important that we have a fallback plan.
103 + const depth = chartData.idToDepthMap.get(selectedFiberID);
104 + return depth !== undefined ? depth - 1 : 0;
105 + }, [chartData, selectedFiberID]);
106 +
107 + const selectedChartNode = useMemo(() => {
108 + if (selectedFiberID !== null) {
109 + return (
110 + chartData.rows[selectedChartNodeIndex].find(
111 + chartNode => chartNode.id === selectedFiberID,
112 + ) || null
113 + );
114 + }
115 + return null;
116 + }, [chartData, selectedFiberID, selectedChartNodeIndex]);
117
118 const itemData = useMemo<ItemData>(
119 () => ({
packages/react-devtools-shared/src/devtools/views/Profiler/CommitTreeBuilder.js
+3 -3
@@ -51,9 +51,9 @@ export function getCommitTree({
51 rootToCommitTreeMap.set(rootID, []);
52 }
53
54 - const commitTrees = ((rootToCommitTreeMap.get(rootID): any): Array<
55 - CommitTree,
56 - >);
54 + const commitTrees = ((rootToCommitTreeMap.get(
55 + rootID,
56 + ): any): Array<CommitTree>);
57
58 if (commitIndex < commitTrees.length) {
59 return commitTrees[commitIndex];
packages/react-devtools-shared/src/devtools/views/Profiler/InteractionListItem.js
+3 -6
@@ -41,12 +41,9 @@ function InteractionListItem({data: itemData, index, style}: Props) {
41 throw Error(`Could not find interaction #${index}`);
42 }
43
44 - const handleClick = useCallback(
45 - () => {
46 - selectInteraction(interaction.id);
47 - },
48 - [interaction, selectInteraction],
49 - );
44 + const handleClick = useCallback(() => {
45 + selectInteraction(interaction.id);
46 + }, [interaction, selectInteraction]);
47
48 const commits = interactionCommits.get(interaction.id) || [];
49
packages/react-devtools-shared/src/devtools/views/Profiler/Interactions.js
+28 -31
@@ -87,45 +87,42 @@ function Interactions({height, width}: {|height: number, width: number|}) {
87 [interactions, selectedInteractionID, selectInteraction],
88 );
89
90 - const itemData = useMemo<ItemData>(
91 - () => {
92 - const interactionCommitSize = parseInt(
93 - getComputedStyle((document.body: any)).getPropertyValue(
94 - '--interaction-commit-size',
95 - ),
96 - 10,
97 - );
98 - const interactionLabelWidth = parseInt(
99 - getComputedStyle((document.body: any)).getPropertyValue(
100 - '--interaction-label-width',
101 - ),
102 - 10,
103 - );
90 + const itemData = useMemo<ItemData>(() => {
91 + const interactionCommitSize = parseInt(
92 + getComputedStyle((document.body: any)).getPropertyValue(
93 + '--interaction-commit-size',
94 + ),
95 + 10,
96 + );
97 + const interactionLabelWidth = parseInt(
98 + getComputedStyle((document.body: any)).getPropertyValue(
99 + '--interaction-label-width',
100 + ),
101 + 10,
102 + );
103
105 - const labelWidth = Math.min(interactionLabelWidth, width / 5);
106 - const timelineWidth = width - labelWidth - interactionCommitSize;
104 + const labelWidth = Math.min(interactionLabelWidth, width / 5);
105 + const timelineWidth = width - labelWidth - interactionCommitSize;
106
108 - return {
109 - chartData,
110 - dataForRoot,
111 - labelWidth,
112 - scaleX: scale(0, chartData.lastInteractionTime, 0, timelineWidth),
113 - selectedInteractionID,
114 - selectCommitIndex,
115 - selectInteraction,
116 - selectTab,
117 - };
118 - },
119 - [
107 + return {
108 chartData,
109 dataForRoot,
110 + labelWidth,
111 + scaleX: scale(0, chartData.lastInteractionTime, 0, timelineWidth),
112 selectedInteractionID,
113 selectCommitIndex,
114 selectInteraction,
115 selectTab,
126 - width,
127 - ],
128 - );
116 + };
117 + }, [
118 + chartData,
119 + dataForRoot,
120 + selectedInteractionID,
121 + selectCommitIndex,
122 + selectInteraction,
123 + selectTab,
124 + width,
125 + ]);
126
127 // If a commit contains no fibers with an actualDuration > 0,
128 // Display a fallback message.
packages/react-devtools-shared/src/devtools/views/Profiler/ProfilerContext.js
+4 -3
@@ -169,9 +169,10 @@ function ProfilerContextController({children}: Props) {
169 store,
170 ]);
171
172 - const [isCommitFilterEnabled, setIsCommitFilterEnabled] = useLocalStorage<
173 - boolean,
174 - >('React::DevTools::isCommitFilterEnabled', false);
172 + const [
173 + isCommitFilterEnabled,
174 + setIsCommitFilterEnabled,
175 + ] = useLocalStorage<boolean>('React::DevTools::isCommitFilterEnabled', false);
176 const [minCommitDuration, setMinCommitDuration] = useLocalStorage<number>(
177 'minCommitDuration',
178 0,
packages/react-devtools-shared/src/devtools/views/Profiler/ProfilingImportExportButtons.js
+58 -64
@@ -33,36 +33,33 @@ export default function ProfilingImportExportButtons() {
33
34 const {dispatch: modalDialogDispatch} = useContext(ModalDialogContext);
35
36 - const downloadData = useCallback(
37 - () => {
38 - if (rootID === null) {
39 - return;
40 - }
36 + const downloadData = useCallback(() => {
37 + if (rootID === null) {
38 + return;
39 + }
40
42 - if (profilingData !== null && downloadRef.current !== null) {
43 - const profilingDataExport = prepareProfilingDataExport(profilingData);
44 - const date = new Date();
45 - const dateString = date
46 - .toLocaleDateString(undefined, {
47 - year: 'numeric',
48 - month: '2-digit',
49 - day: '2-digit',
50 - })
51 - .replace(/\//g, '-');
52 - const timeString = date
53 - .toLocaleTimeString(undefined, {
54 - hour12: false,
55 - })
56 - .replace(/:/g, '-');
57 - downloadFile(
58 - downloadRef.current,
59 - `profiling-data.${dateString}.${timeString}.json`,
60 - JSON.stringify(profilingDataExport, null, 2),
61 - );
62 - }
63 - },
64 - [rootID, profilingData],
65 - );
41 + if (profilingData !== null && downloadRef.current !== null) {
42 + const profilingDataExport = prepareProfilingDataExport(profilingData);
43 + const date = new Date();
44 + const dateString = date
45 + .toLocaleDateString(undefined, {
46 + year: 'numeric',
47 + month: '2-digit',
48 + day: '2-digit',
49 + })
50 + .replace(/\//g, '-');
51 + const timeString = date
52 + .toLocaleTimeString(undefined, {
53 + hour12: false,
54 + })
55 + .replace(/:/g, '-');
56 + downloadFile(
57 + downloadRef.current,
58 + `profiling-data.${dateString}.${timeString}.json`,
59 + JSON.stringify(profilingDataExport, null, 2),
60 + );
61 + }
62 + }, [rootID, profilingData]);
63
64 const uploadData = useCallback(() => {
65 if (inputRef.current !== null) {
@@ -70,41 +67,38 @@ export default function ProfilingImportExportButtons() {
67 }
68 }, []);
69
73 - const handleFiles = useCallback(
74 - () => {
75 - const input = inputRef.current;
76 - if (input !== null && input.files.length > 0) {
77 - const fileReader = new FileReader();
78 - fileReader.addEventListener('load', () => {
79 - try {
80 - const raw = ((fileReader.result: any): string);
81 - const profilingDataExport = ((JSON.parse(
82 - raw,
83 - ): any): ProfilingDataExport);
84 - profilerStore.profilingData = prepareProfilingDataFrontendFromExport(
85 - profilingDataExport,
86 - );
87 - } catch (error) {
88 - modalDialogDispatch({
89 - type: 'SHOW',
90 - title: 'Import failed',
91 - content: (
92 - <Fragment>
93 - <div>The profiling data you selected cannot be imported.</div>
94 - {error !== null && (
95 - <div className={styles.ErrorMessage}>{error.message}</div>
96 - )}
97 - </Fragment>
98 - ),
99 - });
100 - }
101 - });
102 - // TODO (profiling) Handle fileReader errors.
103 - fileReader.readAsText(input.files[0]);
104 - }
105 - },
106 - [modalDialogDispatch, profilerStore],
107 - );
70 + const handleFiles = useCallback(() => {
71 + const input = inputRef.current;
72 + if (input !== null && input.files.length > 0) {
73 + const fileReader = new FileReader();
74 + fileReader.addEventListener('load', () => {
75 + try {
76 + const raw = ((fileReader.result: any): string);
77 + const profilingDataExport = ((JSON.parse(
78 + raw,
79 + ): any): ProfilingDataExport);
80 + profilerStore.profilingData = prepareProfilingDataFrontendFromExport(
81 + profilingDataExport,
82 + );
83 + } catch (error) {
84 + modalDialogDispatch({
85 + type: 'SHOW',
86 + title: 'Import failed',
87 + content: (
88 + <Fragment>
89 + <div>The profiling data you selected cannot be imported.</div>
90 + {error !== null && (
91 + <div className={styles.ErrorMessage}>{error.message}</div>
92 + )}
93 + </Fragment>
94 + ),
95 + });
96 + }
97 + });
98 + // TODO (profiling) Handle fileReader errors.
99 + fileReader.readAsText(input.files[0]);
100 + }
101 + }, [modalDialogDispatch, profilerStore]);
102
103 return (
104 <Fragment>
packages/react-devtools-shared/src/devtools/views/Profiler/ReloadAndProfileButton.js
+12 -14
@@ -39,22 +39,20 @@ export default function ReloadAndProfileButton() {
39 }),
40 [store],
41 );
42 - const {recordChangeDescriptions, supportsReloadAndProfile} = useSubscription<
43 - SubscriptionData,
44 - >(subscription);
42 + const {
43 + recordChangeDescriptions,
44 + supportsReloadAndProfile,
45 + } = useSubscription<SubscriptionData>(subscription);
46
46 - const reloadAndProfile = useCallback(
47 - () => {
48 - // TODO If we want to support reload-and-profile for e.g. React Native,
49 - // we might need to also start profiling here before reloading the app (since DevTools itself isn't reloaded).
50 - // We'd probably want to do this before reloading though, to avoid sending a message on a disconnected port in the browser.
51 - // For now, let's just skip doing it entirely to avoid paying snapshot costs for data we don't need.
52 - // startProfiling();
47 + const reloadAndProfile = useCallback(() => {
48 + // TODO If we want to support reload-and-profile for e.g. React Native,
49 + // we might need to also start profiling here before reloading the app (since DevTools itself isn't reloaded).
50 + // We'd probably want to do this before reloading though, to avoid sending a message on a disconnected port in the browser.
51 + // For now, let's just skip doing it entirely to avoid paying snapshot costs for data we don't need.
52 + // startProfiling();
53
54 - bridge.send('reloadAndProfile', recordChangeDescriptions);
55 - },
56 - [bridge, recordChangeDescriptions],
57 - );
54 + bridge.send('reloadAndProfile', recordChangeDescriptions);
55 + }, [bridge, recordChangeDescriptions]);
56
57 if (!supportsReloadAndProfile) {
58 return null;
packages/react-devtools-shared/src/devtools/views/Profiler/SnapshotCommitList.js
+18 -24
@@ -87,17 +87,14 @@ function List({
87 const prevCommitIndexRef = useRef<number | null>(null);
88
89 // Make sure a newly selected snapshot is fully visible within the list.
90 - useEffect(
91 - () => {
92 - if (selectedFilteredCommitIndex !== prevCommitIndexRef.current) {
93 - prevCommitIndexRef.current = selectedFilteredCommitIndex;
94 - if (selectedFilteredCommitIndex !== null && listRef.current !== null) {
95 - listRef.current.scrollToItem(selectedFilteredCommitIndex);
96 - }
90 + useEffect(() => {
91 + if (selectedFilteredCommitIndex !== prevCommitIndexRef.current) {
92 + prevCommitIndexRef.current = selectedFilteredCommitIndex;
93 + if (selectedFilteredCommitIndex !== null && listRef.current !== null) {
94 + listRef.current.scrollToItem(selectedFilteredCommitIndex);
95 }
98 - },
99 - [listRef, selectedFilteredCommitIndex],
100 - );
96 + }
97 + }, [listRef, selectedFilteredCommitIndex]);
98
99 // When the mouse is down, dragging over a commit should auto-select it.
100 // This provides a nice way for users to swipe across a range of commits to compare them.
@@ -108,21 +105,18 @@ function List({
105 const handleMouseUp = useCallback(() => {
106 setIsMouseDown(false);
107 }, []);
111 - useEffect(
112 - () => {
113 - if (divRef.current === null) {
114 - return () => {};
115 - }
108 + useEffect(() => {
109 + if (divRef.current === null) {
110 + return () => {};
111 + }
112
117 - // It's important to listen to the ownerDocument to support the browser extension.
118 - // Here we use portals to render individual tabs (e.g. Profiler),
119 - // and the root document might belong to a different window.
120 - const ownerDocument = divRef.current.ownerDocument;
121 - ownerDocument.addEventListener('mouseup', handleMouseUp);
122 - return () => ownerDocument.removeEventListener('mouseup', handleMouseUp);
123 - },
124 - [divRef, handleMouseUp],
125 - );
113 + // It's important to listen to the ownerDocument to support the browser extension.
114 + // Here we use portals to render individual tabs (e.g. Profiler),
115 + // and the root document might belong to a different window.
116 + const ownerDocument = divRef.current.ownerDocument;
117 + ownerDocument.addEventListener('mouseup', handleMouseUp);
118 + return () => ownerDocument.removeEventListener('mouseup', handleMouseUp);
119 + }, [divRef, handleMouseUp]);
120
121 const itemSize = useMemo(
122 () => Math.max(minBarWidth, width / filteredCommitIndices.length),
packages/react-devtools-shared/src/devtools/views/Profiler/SnapshotSelector.js
+22 -31
@@ -55,19 +55,16 @@ export default function SnapshotSelector(_: Props) {
55 const numFilteredCommits = filteredCommitIndices.length;
56
57 // Map the (unfiltered) selected commit index to an index within the filtered data.
58 - const selectedFilteredCommitIndex = useMemo(
59 - () => {
60 - if (selectedCommitIndex !== null) {
61 - for (let i = 0; i < filteredCommitIndices.length; i++) {
62 - if (filteredCommitIndices[i] === selectedCommitIndex) {
63 - return i;
64 - }
58 + const selectedFilteredCommitIndex = useMemo(() => {
59 + if (selectedCommitIndex !== null) {
60 + for (let i = 0; i < filteredCommitIndices.length; i++) {
61 + if (filteredCommitIndices[i] === selectedCommitIndex) {
62 + return i;
63 }
64 }
67 - return null;
68 - },
69 - [filteredCommitIndices, selectedCommitIndex],
70 - );
65 + }
66 + return null;
67 + }, [filteredCommitIndices, selectedCommitIndex]);
68
69 // TODO (ProfilerContext) This should be managed by the context controller (reducer).
70 // It doesn't currently know about the filtered commits though (since it doesn't suspend).
@@ -93,26 +90,20 @@ export default function SnapshotSelector(_: Props) {
90 numFilteredCommits;
91 }
92
96 - const viewNextCommit = useCallback(
97 - () => {
98 - let nextCommitIndex = ((selectedFilteredCommitIndex: any): number) + 1;
99 - if (nextCommitIndex === filteredCommitIndices.length) {
100 - nextCommitIndex = 0;
101 - }
102 - selectCommitIndex(filteredCommitIndices[nextCommitIndex]);
103 - },
104 - [selectedFilteredCommitIndex, filteredCommitIndices, selectCommitIndex],
105 - );
106 - const viewPrevCommit = useCallback(
107 - () => {
108 - let nextCommitIndex = ((selectedFilteredCommitIndex: any): number) - 1;
109 - if (nextCommitIndex < 0) {
110 - nextCommitIndex = filteredCommitIndices.length - 1;
111 - }
112 - selectCommitIndex(filteredCommitIndices[nextCommitIndex]);
113 - },
114 - [selectedFilteredCommitIndex, filteredCommitIndices, selectCommitIndex],
115 - );
93 + const viewNextCommit = useCallback(() => {
94 + let nextCommitIndex = ((selectedFilteredCommitIndex: any): number) + 1;
95 + if (nextCommitIndex === filteredCommitIndices.length) {
96 + nextCommitIndex = 0;
97 + }
98 + selectCommitIndex(filteredCommitIndices[nextCommitIndex]);
99 + }, [selectedFilteredCommitIndex, filteredCommitIndices, selectCommitIndex]);
100 + const viewPrevCommit = useCallback(() => {
101 + let nextCommitIndex = ((selectedFilteredCommitIndex: any): number) - 1;
102 + if (nextCommitIndex < 0) {
103 + nextCommitIndex = filteredCommitIndices.length - 1;
104 + }
105 + selectCommitIndex(filteredCommitIndices[nextCommitIndex]);
106 + }, [selectedFilteredCommitIndex, filteredCommitIndices, selectCommitIndex]);
107
108 const handleKeyDown = useCallback(
109 event => {
packages/react-devtools-shared/src/devtools/views/Settings/ComponentsSettings.js
+6 -9
@@ -229,13 +229,10 @@ export default function ComponentsSettings(_: {||}) {
229 // The Store will avoid doing any expensive work unless they've changed.
230 // We just want to batch the work in the event that they do change.
231 const componentFiltersRef = useRef<Array<ComponentFilter>>(componentFilters);
232 - useEffect(
233 - () => {
234 - componentFiltersRef.current = componentFilters;
235 - return () => {};
236 - },
237 - [componentFilters],
238 - );
232 + useEffect(() => {
233 + componentFiltersRef.current = componentFilters;
234 + return () => {};
235 + }, [componentFilters]);
236 useEffect(
237 () => () => {
238 store.componentFilters = [...componentFiltersRef.current];
@@ -282,8 +279,8 @@ export default function ComponentsSettings(_: {||}) {
279 componentFilter.isValid === false
280 ? 'Filter invalid'
281 : componentFilter.isEnabled
285 - ? 'Filter enabled'
286 - : 'Filter disabled'
282 + ? 'Filter enabled'
283 + : 'Filter disabled'
284 }>
285 <ToggleIcon
286 isEnabled={componentFilter.isEnabled}
packages/react-devtools-shared/src/devtools/views/Settings/SettingsContext.js
+59 -72
@@ -74,83 +74,70 @@ function SettingsContextController({
74 'React::DevTools::theme',
75 'auto',
76 );
77 - const [appendComponentStack, setAppendComponentStack] = useLocalStorage<
78 - boolean,
79 - >(LOCAL_STORAGE_SHOULD_PATCH_CONSOLE_KEY, true);
80 - const [traceUpdatesEnabled, setTraceUpdatesEnabled] = useLocalStorage<
81 - boolean,
82 - >(LOCAL_STORAGE_TRACE_UPDATES_ENABLED_KEY, false);
77 + const [
78 + appendComponentStack,
79 + setAppendComponentStack,
80 + ] = useLocalStorage<boolean>(LOCAL_STORAGE_SHOULD_PATCH_CONSOLE_KEY, true);
81 + const [
82 + traceUpdatesEnabled,
83 + setTraceUpdatesEnabled,
84 + ] = useLocalStorage<boolean>(LOCAL_STORAGE_TRACE_UPDATES_ENABLED_KEY, false);
85
84 - const documentElements = useMemo<DocumentElements>(
85 - () => {
86 - const array: Array<HTMLElement> = [
87 - ((document.documentElement: any): HTMLElement),
88 - ];
89 - if (componentsPortalContainer != null) {
90 - array.push(
91 - ((componentsPortalContainer.ownerDocument
92 - .documentElement: any): HTMLElement),
93 - );
94 - }
95 - if (profilerPortalContainer != null) {
96 - array.push(
97 - ((profilerPortalContainer.ownerDocument
98 - .documentElement: any): HTMLElement),
99 - );
100 - }
101 - return array;
102 - },
103 - [componentsPortalContainer, profilerPortalContainer],
104 - );
86 + const documentElements = useMemo<DocumentElements>(() => {
87 + const array: Array<HTMLElement> = [
88 + ((document.documentElement: any): HTMLElement),
89 + ];
90 + if (componentsPortalContainer != null) {
91 + array.push(
92 + ((componentsPortalContainer.ownerDocument
93 + .documentElement: any): HTMLElement),
94 + );
95 + }
96 + if (profilerPortalContainer != null) {
97 + array.push(
98 + ((profilerPortalContainer.ownerDocument
99 + .documentElement: any): HTMLElement),
100 + );
101 + }
102 + return array;
103 + }, [componentsPortalContainer, profilerPortalContainer]);
104
106 - useLayoutEffect(
107 - () => {
108 - switch (displayDensity) {
109 - case 'comfortable':
110 - updateDisplayDensity('comfortable', documentElements);
111 - break;
112 - case 'compact':
113 - updateDisplayDensity('compact', documentElements);
114 - break;
115 - default:
116 - throw Error(`Unsupported displayDensity value "${displayDensity}"`);
117 - }
118 - },
119 - [displayDensity, documentElements],
120 - );
105 + useLayoutEffect(() => {
106 + switch (displayDensity) {
107 + case 'comfortable':
108 + updateDisplayDensity('comfortable', documentElements);
109 + break;
110 + case 'compact':
111 + updateDisplayDensity('compact', documentElements);
112 + break;
113 + default:
114 + throw Error(`Unsupported displayDensity value "${displayDensity}"`);
115 + }
116 + }, [displayDensity, documentElements]);
117
122 - useLayoutEffect(
123 - () => {
124 - switch (theme) {
125 - case 'light':
126 - updateThemeVariables('light', documentElements);
127 - break;
128 - case 'dark':
129 - updateThemeVariables('dark', documentElements);
130 - break;
131 - case 'auto':
132 - updateThemeVariables(browserTheme, documentElements);
133 - break;
134 - default:
135 - throw Error(`Unsupported theme value "${theme}"`);
136 - }
137 - },
138 - [browserTheme, theme, documentElements],
139 - );
118 + useLayoutEffect(() => {
119 + switch (theme) {
120 + case 'light':
121 + updateThemeVariables('light', documentElements);
122 + break;
123 + case 'dark':
124 + updateThemeVariables('dark', documentElements);
125 + break;
126 + case 'auto':
127 + updateThemeVariables(browserTheme, documentElements);
128 + break;
129 + default:
130 + throw Error(`Unsupported theme value "${theme}"`);
131 + }
132 + }, [browserTheme, theme, documentElements]);
133
141 - useEffect(
142 - () => {
143 - bridge.send('updateAppendComponentStack', appendComponentStack);
144 - },
145 - [bridge, appendComponentStack],
146 - );
134 + useEffect(() => {
135 + bridge.send('updateAppendComponentStack', appendComponentStack);
136 + }, [bridge, appendComponentStack]);
137
148 - useEffect(
149 - () => {
150 - bridge.send('setTraceUpdatesEnabled', traceUpdatesEnabled);
151 - },
152 - [bridge, traceUpdatesEnabled],
153 - );
138 + useEffect(() => {
139 + bridge.send('setTraceUpdatesEnabled', traceUpdatesEnabled);
140 + }, [bridge, traceUpdatesEnabled]);
141
142 const value = useMemo(
143 () => ({
packages/react-devtools-shared/src/devtools/views/Settings/SettingsModal.js
+5 -8
@@ -75,14 +75,11 @@ function SettingsModalImpl(_: {||}) {
75 const modalRef = useRef<HTMLDivElement | null>(null);
76 useModalDismissSignal(modalRef, dismissModal);
77
78 - useEffect(
79 - () => {
80 - if (modalRef.current !== null) {
81 - modalRef.current.focus();
82 - }
83 - },
84 - [modalRef],
85 - );
78 + useEffect(() => {
79 + if (modalRef.current !== null) {
80 + modalRef.current.focus();
81 + }
82 + }, [modalRef]);
83
84 let view = null;
85 switch (selectedTabID) {
packages/react-devtools-shared/src/devtools/views/UnsupportedVersionDialog.js
+25 -27
@@ -22,35 +22,32 @@ export default function UnsupportedVersionDialog(_: {||}) {
22 const store = useContext(StoreContext);
23 const [state, setState] = useState<DAILOG_STATE>('dialog-not-shown');
24
25 - useEffect(
26 - () => {
27 - if (state === 'dialog-not-shown') {
28 - const showDialog = () => {
29 - batchedUpdates(() => {
30 - setState('show-dialog');
31 - dispatch({
32 - canBeDismissed: true,
33 - type: 'SHOW',
34 - content: <DialogContent />,
35 - });
25 + useEffect(() => {
26 + if (state === 'dialog-not-shown') {
27 + const showDialog = () => {
28 + batchedUpdates(() => {
29 + setState('show-dialog');
30 + dispatch({
31 + canBeDismissed: true,
32 + type: 'SHOW',
33 + content: <DialogContent />,
34 });
37 - };
35 + });
36 + };
37
39 - if (store.unsupportedRendererVersionDetected) {
40 - showDialog();
41 - } else {
42 - store.addListener('unsupportedRendererVersionDetected', showDialog);
43 - return () => {
44 - store.removeListener(
45 - 'unsupportedRendererVersionDetected',
46 - showDialog,
47 - );
48 - };
49 - }
38 + if (store.unsupportedRendererVersionDetected) {
39 + showDialog();
40 + } else {
41 + store.addListener('unsupportedRendererVersionDetected', showDialog);
42 + return () => {
43 + store.removeListener(
44 + 'unsupportedRendererVersionDetected',
45 + showDialog,
46 + );
47 + };
48 }
51 - },
52 - [state, store],
53 - );
49 + }
50 + }, [state, store]);
51
52 return null;
53 }
@@ -74,7 +71,8 @@ function DialogContent(_: {||}) {
71 rel="noopener noreferrer"
72 href={UNSUPPORTED_VERSION_URL}>
73 install an older version of the extension
77 - </a>.
74 + </a>
75 + .
76 </p>
77 </div>
78 </div>
packages/react-devtools-shared/src/devtools/views/WarnIfLegacyBackendDetected.js
+46 -49
@@ -20,58 +20,55 @@ export default function WarnIfLegacyBackendDetected(_: {||}) {
20 // Detect pairing with legacy v3 backend.
21 // We do this by listening to a message that it broadcasts but the v4 backend doesn't.
22 // In this case the frontend should show upgrade instructions.
23 - useEffect(
24 - () => {
25 - // Wall.listen returns a cleanup function
26 - let unlisten = bridge.wall.listen(message => {
27 - switch (message.type) {
28 - case 'call':
29 - case 'event':
30 - case 'many-events':
31 - // Any of these types indicate the v3 backend.
32 - dispatch({
33 - canBeDismissed: false,
34 - type: 'SHOW',
35 - title: 'DevTools v4 is incompatible with this version of React',
36 - content: <InvalidBackendDetected />,
37 - });
23 + useEffect(() => {
24 + // Wall.listen returns a cleanup function
25 + let unlisten = bridge.wall.listen(message => {
26 + switch (message.type) {
27 + case 'call':
28 + case 'event':
29 + case 'many-events':
30 + // Any of these types indicate the v3 backend.
31 + dispatch({
32 + canBeDismissed: false,
33 + type: 'SHOW',
34 + title: 'DevTools v4 is incompatible with this version of React',
35 + content: <InvalidBackendDetected />,
36 + });
37
39 - // Once we've identified the backend version, it's safe to unsubscribe.
40 - if (typeof unlisten === 'function') {
41 - unlisten();
42 - unlisten = null;
43 - }
44 - break;
45 - default:
46 - break;
47 - }
38 + // Once we've identified the backend version, it's safe to unsubscribe.
39 + if (typeof unlisten === 'function') {
40 + unlisten();
41 + unlisten = null;
42 + }
43 + break;
44 + default:
45 + break;
46 + }
47
49 - switch (message.event) {
50 - case 'isBackendStorageAPISupported':
51 - case 'isNativeStyleEditorSupported':
52 - case 'operations':
53 - case 'overrideComponentFilters':
54 - // Any of these is sufficient to indicate a v4 backend.
55 - // Once we've identified the backend version, it's safe to unsubscribe.
56 - if (typeof unlisten === 'function') {
57 - unlisten();
58 - unlisten = null;
59 - }
60 - break;
61 - default:
62 - break;
63 - }
64 - });
48 + switch (message.event) {
49 + case 'isBackendStorageAPISupported':
50 + case 'isNativeStyleEditorSupported':
51 + case 'operations':
52 + case 'overrideComponentFilters':
53 + // Any of these is sufficient to indicate a v4 backend.
54 + // Once we've identified the backend version, it's safe to unsubscribe.
55 + if (typeof unlisten === 'function') {
56 + unlisten();
57 + unlisten = null;
58 + }
59 + break;
60 + default:
61 + break;
62 + }
63 + });
64
66 - return () => {
67 - if (typeof unlisten === 'function') {
68 - unlisten();
69 - unlisten = null;
70 - }
71 - };
72 - },
73 - [bridge, dispatch],
74 - );
65 + return () => {
66 + if (typeof unlisten === 'function') {
67 + unlisten();
68 + unlisten = null;
69 + }
70 + };
71 + }, [bridge, dispatch]);
72
73 return null;
74 }
packages/react-devtools-shared/src/devtools/views/hooks.js
+106 -121
@@ -112,30 +112,27 @@ export function useIsOverflowing(
112 const [isOverflowing, setIsOverflowing] = useState<boolean>(false);
113
114 // It's important to use a layout effect, so that we avoid showing a flash of overflowed content.
115 - useLayoutEffect(
116 - () => {
117 - if (containerRef.current === null) {
118 - return () => {};
119 - }
115 + useLayoutEffect(() => {
116 + if (containerRef.current === null) {
117 + return () => {};
118 + }
119
121 - const container = ((containerRef.current: any): HTMLDivElement);
120 + const container = ((containerRef.current: any): HTMLDivElement);
121
123 - const handleResize = throttle(
124 - () => setIsOverflowing(container.clientWidth <= totalChildWidth),
125 - 100,
126 - );
122 + const handleResize = throttle(
123 + () => setIsOverflowing(container.clientWidth <= totalChildWidth),
124 + 100,
125 + );
126
128 - handleResize();
127 + handleResize();
128
130 - // It's important to listen to the ownerDocument.defaultView to support the browser extension.
131 - // Here we use portals to render individual tabs (e.g. Profiler),
132 - // and the root document might belong to a different window.
133 - const ownerWindow = container.ownerDocument.defaultView;
134 - ownerWindow.addEventListener('resize', handleResize);
135 - return () => ownerWindow.removeEventListener('resize', handleResize);
136 - },
137 - [containerRef, totalChildWidth],
138 - );
129 + // It's important to listen to the ownerDocument.defaultView to support the browser extension.
130 + // Here we use portals to render individual tabs (e.g. Profiler),
131 + // and the root document might belong to a different window.
132 + const ownerWindow = container.ownerDocument.defaultView;
133 + ownerWindow.addEventListener('resize', handleResize);
134 + return () => ownerWindow.removeEventListener('resize', handleResize);
135 + }, [containerRef, totalChildWidth]);
136
137 return isOverflowing;
138 }
@@ -145,24 +142,21 @@ export function useLocalStorage<T>(
142 key: string,
143 initialValue: T | (() => T),
144 ): [T, (value: T | (() => T)) => void] {
148 - const getValueFromLocalStorage = useCallback(
149 - () => {
150 - try {
151 - const item = localStorageGetItem(key);
152 - if (item != null) {
153 - return JSON.parse(item);
154 - }
155 - } catch (error) {
156 - console.log(error);
157 - }
158 - if (typeof initialValue === 'function') {
159 - return ((initialValue: any): () => T)();
160 - } else {
161 - return initialValue;
145 + const getValueFromLocalStorage = useCallback(() => {
146 + try {
147 + const item = localStorageGetItem(key);
148 + if (item != null) {
149 + return JSON.parse(item);
150 }
163 - },
164 - [initialValue, key],
165 - );
151 + } catch (error) {
152 + console.log(error);
153 + }
154 + if (typeof initialValue === 'function') {
155 + return ((initialValue: any): () => T)();
156 + } else {
157 + return initialValue;
158 + }
159 + }, [initialValue, key]);
160
161 const [storedValue, setStoredValue] = useState(getValueFromLocalStorage);
162
@@ -182,23 +176,20 @@ export function useLocalStorage<T>(
176
177 // Listen for changes to this local storage value made from other windows.
178 // This enables the e.g. "⚛️ Elements" tab to update in response to changes from "⚛️ Settings".
185 - useLayoutEffect(
186 - () => {
187 - const onStorage = event => {
188 - const newValue = getValueFromLocalStorage();
189 - if (key === event.key && storedValue !== newValue) {
190 - setValue(newValue);
191 - }
192 - };
179 + useLayoutEffect(() => {
180 + const onStorage = event => {
181 + const newValue = getValueFromLocalStorage();
182 + if (key === event.key && storedValue !== newValue) {
183 + setValue(newValue);
184 + }
185 + };
186
194 - window.addEventListener('storage', onStorage);
187 + window.addEventListener('storage', onStorage);
188
196 - return () => {
197 - window.removeEventListener('storage', onStorage);
198 - };
199 - },
200 - [getValueFromLocalStorage, key, storedValue, setValue],
201 - );
189 + return () => {
190 + window.removeEventListener('storage', onStorage);
191 + };
192 + }, [getValueFromLocalStorage, key, storedValue, setValue]);
193
194 return [storedValue, setValue];
195 }
@@ -208,47 +199,44 @@ export function useModalDismissSignal(
199 dismissCallback: () => void,
200 dismissOnClickOutside?: boolean = true,
201 ): void {
211 - useEffect(
212 - () => {
213 - if (modalRef.current === null) {
214 - return () => {};
215 - }
216 -
217 - const handleDocumentKeyDown = ({key}: any) => {
218 - if (key === 'Escape') {
219 - dismissCallback();
220 - }
221 - };
222 -
223 - const handleDocumentClick = (event: any) => {
224 - // $FlowFixMe
225 - if (
226 - modalRef.current !== null &&
227 - !modalRef.current.contains(event.target)
228 - ) {
229 - event.stopPropagation();
230 - event.preventDefault();
231 -
232 - dismissCallback();
233 - }
234 - };
202 + useEffect(() => {
203 + if (modalRef.current === null) {
204 + return () => {};
205 + }
206
236 - // It's important to listen to the ownerDocument to support the browser extension.
237 - // Here we use portals to render individual tabs (e.g. Profiler),
238 - // and the root document might belong to a different window.
239 - const ownerDocument = modalRef.current.ownerDocument;
240 - ownerDocument.addEventListener('keydown', handleDocumentKeyDown);
241 - if (dismissOnClickOutside) {
242 - ownerDocument.addEventListener('click', handleDocumentClick);
207 + const handleDocumentKeyDown = ({key}: any) => {
208 + if (key === 'Escape') {
209 + dismissCallback();
210 + }
211 + };
212 +
213 + const handleDocumentClick = (event: any) => {
214 + // $FlowFixMe
215 + if (
216 + modalRef.current !== null &&
217 + !modalRef.current.contains(event.target)
218 + ) {
219 + event.stopPropagation();
220 + event.preventDefault();
221 +
222 + dismissCallback();
223 }
224 + };
225 +
226 + // It's important to listen to the ownerDocument to support the browser extension.
227 + // Here we use portals to render individual tabs (e.g. Profiler),
228 + // and the root document might belong to a different window.
229 + const ownerDocument = modalRef.current.ownerDocument;
230 + ownerDocument.addEventListener('keydown', handleDocumentKeyDown);
231 + if (dismissOnClickOutside) {
232 + ownerDocument.addEventListener('click', handleDocumentClick);
233 + }
234
245 - return () => {
246 - ownerDocument.removeEventListener('keydown', handleDocumentKeyDown);
247 - ownerDocument.removeEventListener('click', handleDocumentClick);
248 - };
249 - },
250 - [modalRef, dismissCallback, dismissOnClickOutside],
251 - );
235 + return () => {
236 + ownerDocument.removeEventListener('keydown', handleDocumentKeyDown);
237 + ownerDocument.removeEventListener('click', handleDocumentClick);
238 + };
239 + }, [modalRef, dismissCallback, dismissOnClickOutside]);
240 }
241
242 // Copied from https://github.com/facebook/react/pull/15022
@@ -276,42 +264,39 @@ export function useSubscription<Value>({
264 });
265 }
266
279 - useEffect(
280 - () => {
281 - let didUnsubscribe = false;
267 + useEffect(() => {
268 + let didUnsubscribe = false;
269
283 - const checkForUpdates = () => {
284 - if (didUnsubscribe) {
285 - return;
270 + const checkForUpdates = () => {
271 + if (didUnsubscribe) {
272 + return;
273 + }
274 +
275 + setState(prevState => {
276 + if (
277 + prevState.getCurrentValue !== getCurrentValue ||
278 + prevState.subscribe !== subscribe
279 + ) {
280 + return prevState;
281 }
282
288 - setState(prevState => {
289 - if (
290 - prevState.getCurrentValue !== getCurrentValue ||
291 - prevState.subscribe !== subscribe
292 - ) {
293 - return prevState;
294 - }
295 -
296 - const value = getCurrentValue();
297 - if (prevState.value === value) {
298 - return prevState;
299 - }
300 -
301 - return {...prevState, value};
302 - });
303 - };
304 - const unsubscribe = subscribe(checkForUpdates);
283 + const value = getCurrentValue();
284 + if (prevState.value === value) {
285 + return prevState;
286 + }
287
306 - checkForUpdates();
288 + return {...prevState, value};
289 + });
290 + };
291 + const unsubscribe = subscribe(checkForUpdates);
292
308 - return () => {
309 - didUnsubscribe = true;
310 - unsubscribe();
311 - };
312 - },
313 - [getCurrentValue, subscribe],
314 - );
293 + checkForUpdates();
294 +
295 + return () => {
296 + didUnsubscribe = true;
297 + unsubscribe();
298 + };
299 + }, [getCurrentValue, subscribe]);
300
301 return state.value;
302 }
packages/react-devtools-shell/src/app/Hydration/index.js
+10 -2
@@ -17,8 +17,16 @@ typedArray[1] = 2;
17 typedArray[2] = 3;
18
19 const arrayOfArrays = [
20 - [['a', 'b', 'c'], ['d', 'e', 'f'], ['h', 'i', 'j']],
21 - [['k', 'l', 'm'], ['n', 'o', 'p'], ['q', 'r', 's']],
20 + [
21 + ['a', 'b', 'c'],
22 + ['d', 'e', 'f'],
23 + ['h', 'i', 'j'],
24 + ],
25 + [
26 + ['k', 'l', 'm'],
27 + ['n', 'o', 'p'],
28 + ['q', 'r', 's'],
29 + ],
30 [['t', 'u', 'v'], ['w', 'x', 'y'], ['z']],
31 [],
32 ];
packages/react-devtools-shell/src/app/InspectableElements/UnserializableProps.js
+8 -2
@@ -11,9 +11,15 @@ import React from 'react';
11 import Immutable from 'immutable';
12
13 const set = new Set(['abc', 123]);
14 -const map = new Map([['name', 'Brian'], ['food', 'sushi']]);
14 +const map = new Map([
15 + ['name', 'Brian'],
16 + ['food', 'sushi'],
17 +]);
18 const setOfSets = new Set([new Set(['a', 'b', 'c']), new Set([1, 2, 3])]);
16 -const mapOfMaps = new Map([['first', map], ['second', map]]);
19 +const mapOfMaps = new Map([
20 + ['first', map],
21 + ['second', map],
22 +]);
23 const typedArray = Int8Array.from([100, -100, 0]);
24 const arrayBuffer = typedArray.buffer;
25 const dataView = new DataView(arrayBuffer);
packages/react-devtools-shell/src/app/InteractionTracing/index.js
+39 -51
@@ -18,66 +18,54 @@ export default function InteractionTracing() {
18 const [count, setCount] = useState(0);
19 const [shouldCascade, setShouldCascade] = useState(false);
20
21 - const handleUpdate = useCallback(
22 - () => {
23 - trace('count', performance.now(), () => {
24 - setTimeout(
25 - wrap(() => {
21 + const handleUpdate = useCallback(() => {
22 + trace('count', performance.now(), () => {
23 + setTimeout(
24 + wrap(() => {
25 + setCount(count + 1);
26 + }),
27 + count * 100,
28 + );
29 + });
30 + }, [count]);
31 +
32 + const handleCascadingUpdate = useCallback(() => {
33 + trace('cascade', performance.now(), () => {
34 + setTimeout(
35 + wrap(() => {
36 + batchedUpdates(() => {
37 setCount(count + 1);
27 - }),
28 - count * 100,
29 - );
30 - });
31 - },
32 - [count],
33 - );
38 + setShouldCascade(true);
39 + });
40 + }),
41 + count * 100,
42 + );
43 + });
44 + }, [count]);
45
35 - const handleCascadingUpdate = useCallback(
36 - () => {
37 - trace('cascade', performance.now(), () => {
46 + const handleMultiple = useCallback(() => {
47 + trace('first', performance.now(), () => {
48 + trace('second', performance.now(), () => {
49 setTimeout(
50 wrap(() => {
40 - batchedUpdates(() => {
41 - setCount(count + 1);
42 - setShouldCascade(true);
43 - });
51 + setCount(count + 1);
52 }),
53 count * 100,
54 );
55 });
48 - },
49 - [count],
50 - );
56 + });
57 + }, [count]);
58
52 - const handleMultiple = useCallback(
53 - () => {
54 - trace('first', performance.now(), () => {
55 - trace('second', performance.now(), () => {
56 - setTimeout(
57 - wrap(() => {
58 - setCount(count + 1);
59 - }),
60 - count * 100,
61 - );
62 - });
63 - });
64 - },
65 - [count],
66 - );
67 -
68 - useEffect(
69 - () => {
70 - if (shouldCascade) {
71 - setTimeout(
72 - wrap(() => {
73 - setShouldCascade(false);
74 - }),
75 - count * 100,
76 - );
77 - }
78 - },
79 - [count, shouldCascade],
80 - );
59 + useEffect(() => {
60 + if (shouldCascade) {
61 + setTimeout(
62 + wrap(() => {
63 + setShouldCascade(false);
64 + }),
65 + count * 100,
66 + );
67 + }
68 + }, [count, shouldCascade]);
69
70 return (
71 <Fragment>
packages/react-devtools-shell/src/app/ToDoList/List.js
+14 -17
@@ -28,23 +28,20 @@ export default function List(props: Props) {
28 ]);
29 const [uid, setUID] = useState<number>(4);
30
31 - const handleClick = useCallback(
32 - () => {
33 - if (newItemText !== '') {
34 - setItems([
35 - ...items,
36 - {
37 - id: uid,
38 - isComplete: false,
39 - text: newItemText,
40 - },
41 - ]);
42 - setUID(uid + 1);
43 - setNewItemText('');
44 - }
45 - },
46 - [newItemText, items, uid],
47 - );
31 + const handleClick = useCallback(() => {
32 + if (newItemText !== '') {
33 + setItems([
34 + ...items,
35 + {
36 + id: uid,
37 + isComplete: false,
38 + text: newItemText,
39 + },
40 + ]);
41 + setUID(uid + 1);
42 + setNewItemText('');
43 + }
44 + }, [newItemText, items, uid]);
45
46 const handleKeyPress = useCallback(
47 event => {
packages/react-devtools-shell/src/app/ToDoList/ListItem.js
+6 -12
@@ -19,19 +19,13 @@ type Props = {|
19 |};
20
21 function ListItem({item, removeItem, toggleItem}: Props) {
22 - const handleDelete = useCallback(
23 - () => {
24 - removeItem(item);
25 - },
26 - [item, removeItem],
27 - );
22 + const handleDelete = useCallback(() => {
23 + removeItem(item);
24 + }, [item, removeItem]);
25
29 - const handleToggle = useCallback(
30 - () => {
31 - toggleItem(item);
32 - },
33 - [item, toggleItem],
34 - );
26 + const handleToggle = useCallback(() => {
27 + toggleItem(item);
28 + }, [item, toggleItem]);
29
30 return (
31 <li className={styles.ListItem}>
packages/react-dom/src/__tests__/ReactComponentLifeCycle-test.js
+7 -9
@@ -1148,9 +1148,11 @@ describe('ReactComponentLifeCycle', () => {
1148 render() {
1149 childInstance = this;
1150 return (
1151 - <div onClick={this.updateState} ref={divRef}>{`remote:${
1152 - this.state.remote
1153 - }, local:${this.state.local}`}</div>
1151 + <div
1152 + onClick={this.updateState}
1153 + ref={
1154 + divRef
1155 + }>{`remote:${this.state.remote}, local:${this.state.local}`}</div>
1156 );
1157 }
1158 }
@@ -1197,17 +1199,13 @@ describe('ReactComponentLifeCycle', () => {
1199 }
1200 getSnapshotBeforeUpdate(prevProps, prevState) {
1201 log.push(
1200 - `getSnapshotBeforeUpdate() prevProps:${prevProps.value} prevState:${
1201 - prevState.value
1202 - }`,
1202 + `getSnapshotBeforeUpdate() prevProps:${prevProps.value} prevState:${prevState.value}`,
1203 );
1204 return 'abc';
1205 }
1206 componentDidUpdate(prevProps, prevState, snapshot) {
1207 log.push(
1208 - `componentDidUpdate() prevProps:${prevProps.value} prevState:${
1209 - prevState.value
1210 - } snapshot:${snapshot}`,
1208 + `componentDidUpdate() prevProps:${prevProps.value} prevState:${prevState.value} snapshot:${snapshot}`,
1209 );
1210 }
1211 render() {
packages/react-dom/src/__tests__/ReactCompositeComponent-test.js
+3 -1
@@ -165,7 +165,9 @@ describe('ReactCompositeComponent', () => {
165 // Old API based on heuristic
166 let container = document.createElement('div');
167 container.innerHTML = markup;
168 - expect(() => ReactDOM.render(<Parent />, container)).toWarnDev(
168 + expect(() =>
169 + ReactDOM.render(<Parent />, container),
170 + ).toWarnDev(
171 'render(): Calling ReactDOM.render() to hydrate server-rendered markup ' +
172 'will stop working in React v17. Replace the ReactDOM.render() call ' +
173 'with ReactDOM.hydrate() if you want React to attach to the server HTML.',
packages/react-dom/src/__tests__/ReactDOMComponent-test.js
+3 -6
@@ -182,24 +182,21 @@ describe('ReactDOMComponent', () => {
182 it('should warn for unknown string event handlers', () => {
183 const container = document.createElement('div');
184 expect(() =>
185 - ReactDOM.render(<div onUnknown="alert(&quot;hack&quot;)" />, container),
185 + ReactDOM.render(<div onUnknown='alert("hack")' />, container),
186 ).toErrorDev(
187 'Warning: Unknown event handler property `onUnknown`. It will be ignored.\n in div (at **)',
188 );
189 expect(container.firstChild.hasAttribute('onUnknown')).toBe(false);
190 expect(container.firstChild.onUnknown).toBe(undefined);
191 expect(() =>
192 - ReactDOM.render(<div onunknown="alert(&quot;hack&quot;)" />, container),
192 + ReactDOM.render(<div onunknown='alert("hack")' />, container),
193 ).toErrorDev(
194 'Warning: Unknown event handler property `onunknown`. It will be ignored.\n in div (at **)',
195 );
196 expect(container.firstChild.hasAttribute('onunknown')).toBe(false);
197 expect(container.firstChild.onunknown).toBe(undefined);
198 expect(() =>
199 - ReactDOM.render(
200 - <div on-unknown="alert(&quot;hack&quot;)" />,
201 - container,
202 - ),
199 + ReactDOM.render(<div on-unknown='alert("hack")' />, container),
200 ).toErrorDev(
201 'Warning: Unknown event handler property `on-unknown`. It will be ignored.\n in div (at **)',
202 );
packages/react-dom/src/__tests__/ReactDOMComponentTree-test.js
+6 -2
@@ -190,7 +190,9 @@ describe('ReactDOMComponentTree', () => {
190 it('finds instance of node that is attempted to be unmounted', () => {
191 const component = <div />;
192 const node = ReactDOM.render(<div>{component}</div>, container);
193 - expect(() => ReactDOM.unmountComponentAtNode(node)).toErrorDev(
193 + expect(() =>
194 + ReactDOM.unmountComponentAtNode(node),
195 + ).toErrorDev(
196 "unmountComponentAtNode(): The node you're attempting to unmount " +
197 'was rendered by React and is not a top-level container. You may ' +
198 'have accidentally passed in a React root node instead of its ' +
@@ -207,7 +209,9 @@ describe('ReactDOMComponentTree', () => {
209 );
210 const anotherComponent = <div />;
211 const instance = ReactDOM.render(component, container);
210 - expect(() => ReactDOM.render(anotherComponent, instance)).toErrorDev(
212 + expect(() =>
213 + ReactDOM.render(anotherComponent, instance),
214 + ).toErrorDev(
215 'render(...): Replacing React-rendered children with a new root ' +
216 'component. If you intended to update the children of this node, ' +
217 'you should instead have the existing children update their state ' +
packages/react-dom/src/__tests__/ReactDOMFiber-test.js
+6 -2
@@ -1151,7 +1151,9 @@ describe('ReactDOMFiber', () => {
1151 expect(container.innerHTML).toBe('<div>bar</div>');
1152 // then we mess with the DOM before an update
1153 container.innerHTML = '<div>MEOW.</div>';
1154 - expect(() => ReactDOM.render(<div>baz</div>, container)).toErrorDev(
1154 + expect(() =>
1155 + ReactDOM.render(<div>baz</div>, container),
1156 + ).toErrorDev(
1157 'render(...): ' +
1158 'It looks like the React-rendered content of this container was ' +
1159 'removed without using React. This is not supported and will ' +
@@ -1168,7 +1170,9 @@ describe('ReactDOMFiber', () => {
1170 expect(container.innerHTML).toBe('<div>bar</div>');
1171 // then we mess with the DOM before an update
1172 container.innerHTML = '';
1171 - expect(() => ReactDOM.render(<div>baz</div>, container)).toErrorDev(
1173 + expect(() =>
1174 + ReactDOM.render(<div>baz</div>, container),
1175 + ).toErrorDev(
1176 'render(...): ' +
1177 'It looks like the React-rendered content of this container was ' +
1178 'removed without using React. This is not supported and will ' +
packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.internal.js
+5 -8
@@ -593,14 +593,11 @@ describe('ReactDOMFiberAsync', () => {
593
594 function App({label}) {
595 const [step, setStep] = useState(0);
596 - useEffect(
597 - () => {
598 - if (step < 3) {
599 - setStep(step + 1);
600 - }
601 - },
602 - [step],
603 - );
596 + useEffect(() => {
597 + if (step < 3) {
598 + setStep(step + 1);
599 + }
600 + }, [step]);
601
602 // The component should keep re-rendering itself until `step` is 3.
603 return step === 3 ? 'Finished' : 'Unresolved';
packages/react-dom/src/__tests__/ReactDOMServerIntegrationAttributes-test.js
+1 -4
@@ -636,10 +636,7 @@ describe('ReactDOMServerIntegration', () => {
636 });
637
638 itRenders('no unknown events', async render => {
639 - const e = await render(
640 - <div onunknownevent="alert(&quot;hack&quot;)" />,
641 - 1,
642 - );
639 + const e = await render(<div onunknownevent='alert("hack")' />, 1);
640 expect(e.getAttribute('onunknownevent')).toBe(null);
641 });
642
packages/react-dom/src/__tests__/ReactDOMServerIntegrationElements-test.js
+22 -17
@@ -258,8 +258,7 @@ describe('ReactDOMServerIntegration', () => {
258 <div>
259 {[['a'], 'b']}
260 <div>
261 - <X key="1" />
262 - d
261 + <X key="1" />d
262 </div>
263 e
264 </div>,
@@ -493,11 +492,13 @@ describe('ReactDOMServerIntegration', () => {
492 // Put dangerouslySetInnerHTML one level deeper because otherwise
493 // hydrating from a bad markup would cause a mismatch (since we don't
494 // patch dangerouslySetInnerHTML as text content).
496 - const e = (await render(
497 - <div>
498 - <span dangerouslySetInnerHTML={{__html: 0}} />
499 - </div>,
500 - )).firstChild;
495 + const e = (
496 + await render(
497 + <div>
498 + <span dangerouslySetInnerHTML={{__html: 0}} />
499 + </div>,
500 + )
501 + ).firstChild;
502 expect(e.childNodes.length).toBe(1);
503 expect(e.firstChild.nodeType).toBe(TEXT_NODE_TYPE);
504 expect(e.textContent).toBe('0');
@@ -507,11 +508,13 @@ describe('ReactDOMServerIntegration', () => {
508 // Put dangerouslySetInnerHTML one level deeper because otherwise
509 // hydrating from a bad markup would cause a mismatch (since we don't
510 // patch dangerouslySetInnerHTML as text content).
510 - const e = (await render(
511 - <div>
512 - <span dangerouslySetInnerHTML={{__html: false}} />
513 - </div>,
514 - )).firstChild;
511 + const e = (
512 + await render(
513 + <div>
514 + <span dangerouslySetInnerHTML={{__html: false}} />
515 + </div>,
516 + )
517 + ).firstChild;
518 expect(e.childNodes.length).toBe(1);
519 expect(e.firstChild.nodeType).toBe(TEXT_NODE_TYPE);
520 expect(e.firstChild.data).toBe('false');
@@ -523,11 +526,13 @@ describe('ReactDOMServerIntegration', () => {
526 // Put dangerouslySetInnerHTML one level deeper because otherwise
527 // hydrating from a bad markup would cause a mismatch (since we don't
528 // patch dangerouslySetInnerHTML as text content).
526 - const e = (await render(
527 - <div>
528 - <span dangerouslySetInnerHTML={{__html: 'hello'}} />
529 - </div>,
530 - )).firstChild;
529 + const e = (
530 + await render(
531 + <div>
532 + <span dangerouslySetInnerHTML={{__html: 'hello'}} />
533 + </div>,
534 + )
535 + ).firstChild;
536 expect(e.childNodes.length).toBe(1);
537 expect(e.firstChild.nodeType).toBe(TEXT_NODE_TYPE);
538 expect(e.textContent).toBe('hello');
packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.internal.js
+12 -21
@@ -322,13 +322,10 @@ describe('ReactDOMServerHooks', () => {
322 itRenders('basic render', async render => {
323 function CapitalizedText(props) {
324 const text = props.text;
325 - const capitalizedText = useMemo(
326 - () => {
327 - yieldValue(`Capitalize '${text}'`);
328 - return text.toUpperCase();
329 - },
330 - [text],
331 - );
325 + const capitalizedText = useMemo(() => {
326 + yieldValue(`Capitalize '${text}'`);
327 + return text.toUpperCase();
328 + }, [text]);
329 return <Text text={capitalizedText} />;
330 }
331
@@ -360,13 +357,10 @@ describe('ReactDOMServerHooks', () => {
357 async render => {
358 function CapitalizedText(props) {
359 const [text, setText] = useState(props.text);
363 - const capitalizedText = useMemo(
364 - () => {
365 - yieldValue(`Capitalize '${text}'`);
366 - return text.toUpperCase();
367 - },
368 - [text],
369 - );
360 + const capitalizedText = useMemo(() => {
361 + yieldValue(`Capitalize '${text}'`);
362 + return text.toUpperCase();
363 + }, [text]);
364
365 if (text === 'hello') {
366 setText('hello, world.');
@@ -391,13 +385,10 @@ describe('ReactDOMServerHooks', () => {
385 function CapitalizedText(props) {
386 const [text, setText] = useState(props.text);
387 const [count, setCount] = useState(0);
394 - const capitalizedText = useMemo(
395 - () => {
396 - yieldValue(`Capitalize '${text}'`);
397 - return text.toUpperCase();
398 - },
399 - [text],
400 - );
388 + const capitalizedText = useMemo(() => {
389 + yieldValue(`Capitalize '${text}'`);
390 + return text.toUpperCase();
391 + }, [text]);
392
393 yieldValue(count);
394
packages/react-dom/src/__tests__/ReactDOMSuspensePlaceholder-test.js
+10 -7
@@ -33,13 +33,16 @@ describe('ReactDOMSuspensePlaceholder', () => {
33 container = document.createElement('div');
34 document.body.appendChild(container);
35
36 - TextResource = ReactCache.unstable_createResource(([text, ms = 0]) => {
37 - return new Promise((resolve, reject) =>
38 - setTimeout(() => {
39 - resolve(text);
40 - }, ms),
41 - );
42 - }, ([text, ms]) => text);
36 + TextResource = ReactCache.unstable_createResource(
37 + ([text, ms = 0]) => {
38 + return new Promise((resolve, reject) =>
39 + setTimeout(() => {
40 + resolve(text);
41 + }, ms),
42 + );
43 + },
44 + ([text, ms]) => text,
45 + );
46 });
47
48 afterEach(() => {
packages/react-dom/src/__tests__/ReactFunctionComponent-test.js
+5 -5
@@ -163,11 +163,11 @@ describe('ReactFunctionComponent', () => {
163 : // It happens because we don't save _owner in production for
164 // function components.
165 'Element ref was specified as a string (me) but no owner was set. This could happen for one of' +
166 - ' the following reasons:\n' +
167 - '1. You may be adding a ref to a function component\n' +
168 - "2. You may be adding a ref to a component that was not created inside a component's render method\n" +
169 - '3. You have multiple copies of React loaded\n' +
170 - 'See https://fb.me/react-refs-must-have-owner for more information.',
166 + ' the following reasons:\n' +
167 + '1. You may be adding a ref to a function component\n' +
168 + "2. You may be adding a ref to a component that was not created inside a component's render method\n" +
169 + '3. You have multiple copies of React loaded\n' +
170 + 'See https://fb.me/react-refs-must-have-owner for more information.',
171 );
172 });
173
packages/react-dom/src/__tests__/ReactMount-test.js
+12 -4
@@ -59,7 +59,9 @@ describe('ReactMount', () => {
59 }
60 }
61
62 - expect(() => ReactTestUtils.renderIntoDocument(Component)).toErrorDev(
62 + expect(() =>
63 + ReactTestUtils.renderIntoDocument(Component),
64 + ).toErrorDev(
65 'Functions are not valid as a React child. ' +
66 'This may happen if you return a Component instead of <Component /> from render. ' +
67 'Or maybe you meant to call this function rather than return it.',
@@ -125,7 +127,9 @@ describe('ReactMount', () => {
127 const container = document.createElement('container');
128 container.innerHTML = ReactDOMServer.renderToString(<div />) + ' ';
129
128 - expect(() => ReactDOM.hydrate(<div />, container)).toErrorDev(
130 + expect(() =>
131 + ReactDOM.hydrate(<div />, container),
132 + ).toErrorDev(
133 'Did not expect server HTML to contain the text node " " in <container>.',
134 {withoutStack: true},
135 );
@@ -195,7 +199,9 @@ describe('ReactMount', () => {
199 // Test that blasting away children throws a warning
200 const rootNode = container.firstChild;
201
198 - expect(() => ReactDOM.render(<span />, rootNode)).toErrorDev(
202 + expect(() =>
203 + ReactDOM.render(<span />, rootNode),
204 + ).toErrorDev(
205 'Warning: render(...): Replacing React-rendered children with a new ' +
206 'root component. If you intended to update the children of this node, ' +
207 'you should instead have the existing children update their state and ' +
@@ -223,7 +229,9 @@ describe('ReactMount', () => {
229 // Make sure ReactDOM and ReactDOMOther are different copies
230 expect(ReactDOM).not.toEqual(ReactDOMOther);
231
226 - expect(() => ReactDOMOther.unmountComponentAtNode(container)).toErrorDev(
232 + expect(() =>
233 + ReactDOMOther.unmountComponentAtNode(container),
234 + ).toErrorDev(
235 "Warning: unmountComponentAtNode(): The node you're attempting to unmount " +
236 'was rendered by another copy of React.',
237 {withoutStack: true},
packages/react-dom/src/__tests__/ReactMountDestruction-test.js
+6 -2
@@ -50,7 +50,9 @@ describe('ReactMount', () => {
50
51 // Test that unmounting at a root node gives a helpful warning
52 const rootDiv = mainContainerDiv.firstChild;
53 - expect(() => ReactDOM.unmountComponentAtNode(rootDiv)).toErrorDev(
53 + expect(() =>
54 + ReactDOM.unmountComponentAtNode(rootDiv),
55 + ).toErrorDev(
56 "Warning: unmountComponentAtNode(): The node you're attempting to " +
57 'unmount was rendered by React and is not a top-level container. You ' +
58 'may have accidentally passed in a React root node instead of its ' +
@@ -73,7 +75,9 @@ describe('ReactMount', () => {
75
76 // Test that unmounting at a non-root node gives a different warning
77 const nonRootDiv = mainContainerDiv.firstChild.firstChild;
76 - expect(() => ReactDOM.unmountComponentAtNode(nonRootDiv)).toErrorDev(
78 + expect(() =>
79 + ReactDOM.unmountComponentAtNode(nonRootDiv),
80 + ).toErrorDev(
81 "Warning: unmountComponentAtNode(): The node you're attempting to " +
82 'unmount was rendered by React and is not a top-level container. ' +
83 'Instead, have the parent component update its state and rerender in ' +
packages/react-dom/src/__tests__/ReactMultiChild-test.js
+23 -8
@@ -281,7 +281,16 @@ describe('ReactMultiChild', () => {
281 it('should warn for using maps as children with owner info', () => {
282 class Parent extends React.Component {
283 render() {
284 - return <div>{new Map([['foo', 0], ['bar', 1]])}</div>;
284 + return (
285 + <div>
286 + {
287 + new Map([
288 + ['foo', 0],
289 + ['bar', 1],
290 + ])
291 + }
292 + </div>
293 + );
294 }
295 }
296 const container = document.createElement('div');
@@ -296,8 +305,8 @@ describe('ReactMultiChild', () => {
305
306 it('should warn for using generators as children', () => {
307 function* Foo() {
299 - yield <h1 key="1">Hello</h1>;
300 - yield <h1 key="2">World</h1>;
308 + yield (<h1 key="1">Hello</h1>);
309 + yield (<h1 key="2">World</h1>);
310 }
311
312 const div = document.createElement('div');
@@ -318,8 +327,8 @@ describe('ReactMultiChild', () => {
327 it('should not warn for using generators in legacy iterables', () => {
328 const fooIterable = {
329 '@@iterator': function*() {
321 - yield <h1 key="1">Hello</h1>;
322 - yield <h1 key="2">World</h1>;
330 + yield (<h1 key="1">Hello</h1>);
331 + yield (<h1 key="2">World</h1>);
332 },
333 };
334
@@ -338,8 +347,8 @@ describe('ReactMultiChild', () => {
347 it('should not warn for using generators in modern iterables', () => {
348 const fooIterable = {
349 [Symbol.iterator]: function*() {
341 - yield <h1 key="1">Hello</h1>;
342 - yield <h1 key="2">World</h1>;
350 + yield (<h1 key="1">Hello</h1>);
351 + yield (<h1 key="2">World</h1>);
352 },
353 };
354
@@ -374,7 +383,13 @@ describe('ReactMultiChild', () => {
383 class Letters extends React.Component {
384 render() {
385 const letters = this.props.letters.split('');
377 - return <div>{letters.map(c => <Letter key={c} char={c} />)}</div>;
386 + return (
387 + <div>
388 + {letters.map(c => (
389 + <Letter key={c} char={c} />
390 + ))}
391 + </div>
392 + );
393 }
394 }
395
packages/react-dom/src/__tests__/ReactRenderDocument-test.js
+3 -1
@@ -35,7 +35,9 @@ describe('rendering React components at document', () => {
35
36 describe('with old implicit hydration API', () => {
37 function expectDeprecationWarningWithFiber(callback) {
38 - expect(callback).toWarnDev(
38 + expect(
39 + callback,
40 + ).toWarnDev(
41 'render(): Calling ReactDOM.render() to hydrate server-rendered markup ' +
42 'will stop working in React v17. Replace the ReactDOM.render() call ' +
43 'with ReactDOM.hydrate() if you want React to attach to the server HTML.',
packages/react-dom/src/__tests__/ReactServerRendering-test.js
+6 -2
@@ -644,7 +644,9 @@ describe('ReactDOMServer', () => {
644 }
645
646 ReactDOMServer.renderToString(<Foo />);
647 - expect(() => jest.runOnlyPendingTimers()).toErrorDev(
647 + expect(() =>
648 + jest.runOnlyPendingTimers(),
649 + ).toErrorDev(
650 'Warning: setState(...): Can only update a mounting component.' +
651 ' This usually means you called setState() outside componentWillMount() on the server.' +
652 ' This is a no-op.\n\nPlease check the code for the Foo component.',
@@ -672,7 +674,9 @@ describe('ReactDOMServer', () => {
674 }
675
676 ReactDOMServer.renderToString(<Baz />);
675 - expect(() => jest.runOnlyPendingTimers()).toErrorDev(
677 + expect(() =>
678 + jest.runOnlyPendingTimers(),
679 + ).toErrorDev(
680 'Warning: forceUpdate(...): Can only update a mounting component. ' +
681 'This usually means you called forceUpdate() outside componentWillMount() on the server. ' +
682 'This is a no-op.\n\nPlease check the code for the Baz component.',
packages/react-dom/src/__tests__/ReactTestUtils-test.js
+3 -1
@@ -53,7 +53,9 @@ describe('ReactTestUtils', () => {
53 MockedComponent.prototype.render = jest.fn();
54
55 // Patch it up so it returns its children.
56 - expect(() => ReactTestUtils.mockComponent(MockedComponent)).toWarnDev(
56 + expect(() =>
57 + ReactTestUtils.mockComponent(MockedComponent),
58 + ).toWarnDev(
59 'ReactTestUtils.mockComponent() is deprecated. ' +
60 'Use shallow rendering or jest.mock() instead.\n\n' +
61 'See https://fb.me/test-utils-mock-component for more information.',
packages/react-dom/src/__tests__/ReactTestUtilsAct-test.js
+7 -13
@@ -337,12 +337,9 @@ function runActTests(label, render, unmount, rerender) {
337 await null;
338 setState(x => x + 1);
339 }
340 - React.useEffect(
341 - () => {
342 - ticker();
343 - },
344 - [Math.min(state, 4)],
345 - );
340 + React.useEffect(() => {
341 + ticker();
342 + }, [Math.min(state, 4)]);
343 return state;
344 }
345
@@ -521,13 +518,10 @@ function runActTests(label, render, unmount, rerender) {
518 await null;
519 setState(x => x + 1);
520 }
524 - React.useEffect(
525 - () => {
526 - Scheduler.unstable_yieldValue(state);
527 - ticker();
528 - },
529 - [Math.min(state, 4)],
530 - );
521 + React.useEffect(() => {
522 + Scheduler.unstable_yieldValue(state);
523 + ticker();
524 + }, [Math.min(state, 4)]);
525 return state;
526 }
527
packages/react-dom/src/__tests__/ReactTestUtilsActUnmockedScheduler-test.js
+4 -7
@@ -147,13 +147,10 @@ it('can handle cascading promises', async () => {
147 await null;
148 setState(x => x + 1);
149 }
150 - React.useEffect(
151 - () => {
152 - yields.push(state);
153 - ticker();
154 - },
155 - [Math.min(state, 4)],
156 - );
150 + React.useEffect(() => {
151 + yields.push(state);
152 + ticker();
153 + }, [Math.min(state, 4)]);
154 return state;
155 }
156
packages/react-dom/src/__tests__/renderSubtreeIntoContainer-test.js
+5 -5
@@ -312,11 +312,11 @@ describe('renderSubtreeIntoContainer', () => {
312 }).toThrow(
313 __DEV__
314 ? '_processChildContext is not available in React 16+. This likely ' +
315 - 'means you have multiple copies of React and are attempting to nest ' +
316 - 'a React 15 tree inside a React 16 tree using ' +
317 - "unstable_renderSubtreeIntoContainer, which isn't supported. Try to " +
318 - 'make sure you have only one copy of React (and ideally, switch to ' +
319 - 'ReactDOM.createPortal).'
315 + 'means you have multiple copies of React and are attempting to nest ' +
316 + 'a React 15 tree inside a React 16 tree using ' +
317 + "unstable_renderSubtreeIntoContainer, which isn't supported. Try to " +
318 + 'make sure you have only one copy of React (and ideally, switch to ' +
319 + 'ReactDOM.createPortal).'
320 : "Cannot read property '_processChildContext' of undefined",
321 );
322 });
packages/react-dom/src/client/ReactDOMLegacy.js
+2 -2
@@ -385,9 +385,9 @@ export function unmountComponentAtNode(container: DOMContainer) {
385 'was rendered by React and is not a top-level container. %s',
386 isContainerReactRoot
387 ? 'You may have accidentally passed in a React root node instead ' +
388 - 'of its container.'
388 + 'of its container.'
389 : 'Instead, have the parent component update its state and ' +
390 - 'rerender in order to remove this component.',
390 + 'rerender in order to remove this component.',
391 );
392 }
393 }
packages/react-dom/src/events/SelectEventPlugin.js
+2 -2
@@ -94,8 +94,8 @@ function getEventTargetDocument(eventTarget) {
94 return eventTarget.window === eventTarget
95 ? eventTarget.document
96 : eventTarget.nodeType === DOCUMENT_NODE
97 - ? eventTarget
98 - : eventTarget.ownerDocument;
97 + ? eventTarget
98 + : eventTarget.ownerDocument;
99 }
100
101 /**
packages/react-dom/src/events/SyntheticWheelEvent.js
+9 -9
@@ -16,20 +16,20 @@ const SyntheticWheelEvent = SyntheticMouseEvent.extend({
16 return 'deltaX' in event
17 ? event.deltaX
18 : // Fallback to `wheelDeltaX` for Webkit and normalize (right is positive).
19 - 'wheelDeltaX' in event
20 - ? -event.wheelDeltaX
21 - : 0;
19 + 'wheelDeltaX' in event
20 + ? -event.wheelDeltaX
21 + : 0;
22 },
23 deltaY(event) {
24 return 'deltaY' in event
25 ? event.deltaY
26 : // Fallback to `wheelDeltaY` for Webkit and normalize (down is positive).
27 - 'wheelDeltaY' in event
28 - ? -event.wheelDeltaY
29 - : // Fallback to `wheelDelta` for IE<9 and normalize (down is positive).
30 - 'wheelDelta' in event
31 - ? -event.wheelDelta
32 - : 0;
27 + 'wheelDeltaY' in event
28 + ? -event.wheelDeltaY
29 + : // Fallback to `wheelDelta` for IE<9 and normalize (down is positive).
30 + 'wheelDelta' in event
31 + ? -event.wheelDelta
32 + : 0;
33 },
34 deltaZ: null,
35
packages/react-dom/src/events/__tests__/SimpleEventPlugin-test.internal.js
+1 -3
@@ -388,9 +388,7 @@ describe('SimpleEventPlugin', function() {
388 class Button extends React.Component {
389 state = {lowPriCount: 0};
390 render() {
391 - const text = `High-pri count: ${
392 - this.props.highPriCount
393 - }, Low-pri count: ${this.state.lowPriCount}`;
391 + const text = `High-pri count: ${this.props.highPriCount}, Low-pri count: ${this.state.lowPriCount}`;
392 Scheduler.unstable_yieldValue(text);
393 return (
394 <button
packages/react-dom/src/events/__tests__/SyntheticEvent-test.js
+15 -14
@@ -151,18 +151,15 @@ describe('SyntheticEvent', () => {
151 'See https://fb.me/react-event-pooling for more information.';
152
153 // once for each property accessed
154 - expect(() => expect(syntheticEvent.type).toBe(null)).toErrorDev(
155 - getExpectedWarning('type'),
156 - {withoutStack: true},
157 - );
158 - expect(() => expect(syntheticEvent.nativeEvent).toBe(null)).toErrorDev(
159 - getExpectedWarning('nativeEvent'),
160 - {withoutStack: true},
161 - );
162 - expect(() => expect(syntheticEvent.target).toBe(null)).toErrorDev(
163 - getExpectedWarning('target'),
164 - {withoutStack: true},
165 - );
154 + expect(() =>
155 + expect(syntheticEvent.type).toBe(null),
156 + ).toErrorDev(getExpectedWarning('type'), {withoutStack: true});
157 + expect(() =>
158 + expect(syntheticEvent.nativeEvent).toBe(null),
159 + ).toErrorDev(getExpectedWarning('nativeEvent'), {withoutStack: true});
160 + expect(() =>
161 + expect(syntheticEvent.target).toBe(null),
162 + ).toErrorDev(getExpectedWarning('target'), {withoutStack: true});
163
164 expect(expectedCount).toBe(1);
165 });
@@ -211,7 +208,9 @@ describe('SyntheticEvent', () => {
208 event.initEvent('click', true, true);
209 node.dispatchEvent(event);
210
214 - expect(() => syntheticEvent.preventDefault()).toErrorDev(
211 + expect(() =>
212 + syntheticEvent.preventDefault(),
213 + ).toErrorDev(
214 'Warning: This synthetic event is reused for performance reasons. If ' +
215 "you're seeing this, you're accessing the method `preventDefault` on a " +
216 'released/nullified synthetic event. This is a no-op function. If you must ' +
@@ -238,7 +237,9 @@ describe('SyntheticEvent', () => {
237
238 node.dispatchEvent(event);
239
241 - expect(() => syntheticEvent.stopPropagation()).toErrorDev(
240 + expect(() =>
241 + syntheticEvent.stopPropagation(),
242 + ).toErrorDev(
243 'Warning: This synthetic event is reused for performance reasons. If ' +
244 "you're seeing this, you're accessing the method `stopPropagation` on a " +
245 'released/nullified synthetic event. This is a no-op function. If you must ' +
packages/react-interactions/accessibility/src/FocusContain.js
+12 -15
@@ -64,22 +64,19 @@ export default function FocusContain({
64 }
65 },
66 });
67 - useLayoutEffect(
68 - () => {
69 - const scope = scopeRef.current;
70 - if (
71 - scope !== null &&
72 - disabled !== true &&
73 - !scope.containsNode(document.activeElement)
74 - ) {
75 - const fistElem = scope.queryFirstNode(scopeQuery);
76 - if (fistElem !== null) {
77 - fistElem.focus();
78 - }
67 + useLayoutEffect(() => {
68 + const scope = scopeRef.current;
69 + if (
70 + scope !== null &&
71 + disabled !== true &&
72 + !scope.containsNode(document.activeElement)
73 + ) {
74 + const fistElem = scope.queryFirstNode(scopeQuery);
75 + if (fistElem !== null) {
76 + fistElem.focus();
77 }
80 - },
81 - [disabled],
82 - );
78 + }
79 + }, [disabled]);
80
81 return (
82 <FocusContainScope
packages/react-interactions/events/src/dom/Press.js
+3 -3
@@ -95,9 +95,9 @@ function isValidKey(e): boolean {
95 const {tagName, isContentEditable} = (target: any);
96 return (
97 (key === 'Enter' || key === ' ' || key === 'Spacebar') &&
98 - (tagName !== 'INPUT' &&
99 - tagName !== 'TEXTAREA' &&
100 - isContentEditable !== true)
98 + tagName !== 'INPUT' &&
99 + tagName !== 'TEXTAREA' &&
100 + isContentEditable !== true
101 );
102 }
103
packages/react-interactions/events/src/dom/PressLegacy.js
+7 -4
@@ -339,9 +339,9 @@ function isValidKeyboardEvent(nativeEvent: Object): boolean {
339 // "Spacebar" is for IE 11
340 return (
341 (key === 'Enter' || key === ' ' || key === 'Spacebar') &&
342 - (tagName !== 'INPUT' &&
343 - tagName !== 'TEXTAREA' &&
344 - isContentEditable !== true)
342 + tagName !== 'INPUT' &&
343 + tagName !== 'TEXTAREA' &&
344 + isContentEditable !== true
345 );
346 }
347
@@ -480,7 +480,10 @@ function updateIsPressWithinResponderRegion(
480 bottom != null &&
481 x !== null &&
482 y !== null &&
483 - (x >= left && x <= right && y >= top && y <= bottom);
483 + x >= left &&
484 + x <= right &&
485 + y >= top &&
486 + y <= bottom;
487 }
488
489 // After some investigation work, screen reader virtual
packages/react-native-renderer/src/ReactNativeHostConfig.js
+4 -5
@@ -163,11 +163,10 @@ export function finalizeInitialChildren(
163
164 // Map from child objects to native tags.
165 // Either way we need to pass a copy of the Array to prevent it from being frozen.
166 - const nativeTags = parentInstance._children.map(
167 - child =>
168 - typeof child === 'number'
169 - ? child // Leaf node (eg text)
170 - : child._nativeTag,
166 + const nativeTags = parentInstance._children.map(child =>
167 + typeof child === 'number'
168 + ? child // Leaf node (eg text)
169 + : child._nativeTag,
170 );
171
172 UIManager.setChildren(
packages/react-native-renderer/src/__tests__/ReactFabric-test.internal.js
+13 -7
@@ -280,11 +280,9 @@ describe('ReactFabric', () => {
280 expect(nativeFabricUIManager.dispatchCommand).not.toBeCalled();
281 ReactFabric.dispatchCommand(viewRef, 'updateCommand', [10, 20]);
282 expect(nativeFabricUIManager.dispatchCommand).toHaveBeenCalledTimes(1);
283 - expect(nativeFabricUIManager.dispatchCommand).toHaveBeenCalledWith(
284 - expect.any(Object),
285 - 'updateCommand',
286 - [10, 20],
287 - );
283 + expect(
284 + nativeFabricUIManager.dispatchCommand,
285 + ).toHaveBeenCalledWith(expect.any(Object), 'updateCommand', [10, 20]);
286 });
287 });
288
@@ -550,7 +548,11 @@ describe('ReactFabric', () => {
548 render() {
549 const chars = this.props.chars.split('');
550 return (
553 - <View>{chars.map(text => <View key={text} title={text} />)}</View>
551 + <View>
552 + {chars.map(text => (
553 + <View key={text} title={text} />
554 + ))}
555 + </View>
556 );
557 }
558 }
@@ -586,7 +588,11 @@ describe('ReactFabric', () => {
588 render() {
589 const chars = this.state.chars.split('');
590 return (
589 - <View>{chars.map(text => <View key={text} title={text} />)}</View>
591 + <View>
592 + {chars.map(text => (
593 + <View key={text} title={text} />
594 + ))}
595 + </View>
596 );
597 }
598 }
packages/react-native-renderer/src/__tests__/ReactFabricAndNative-test.internal.js
+6 -10
@@ -87,11 +87,9 @@ describe('created with ReactFabric called with ReactNative', () => {
87 expect(nativeFabricUIManager.dispatchCommand).not.toBeCalled();
88 ReactNative.dispatchCommand(ref.current, 'myCommand', [10, 20]);
89 expect(nativeFabricUIManager.dispatchCommand).toHaveBeenCalledTimes(1);
90 - expect(nativeFabricUIManager.dispatchCommand).toHaveBeenCalledWith(
91 - expect.any(Object),
92 - 'myCommand',
93 - [10, 20],
94 - );
90 + expect(
91 + nativeFabricUIManager.dispatchCommand,
92 + ).toHaveBeenCalledWith(expect.any(Object), 'myCommand', [10, 20]);
93 expect(UIManager.dispatchViewManagerCommand).not.toBeCalled();
94 });
95 });
@@ -167,11 +165,9 @@ describe('created with ReactNative called with ReactFabric', () => {
165 expect(UIManager.dispatchViewManagerCommand).not.toBeCalled();
166 ReactFabric.dispatchCommand(ref.current, 'myCommand', [10, 20]);
167 expect(UIManager.dispatchViewManagerCommand).toHaveBeenCalledTimes(1);
170 - expect(UIManager.dispatchViewManagerCommand).toHaveBeenCalledWith(
171 - expect.any(Number),
172 - 'myCommand',
173 - [10, 20],
174 - );
168 + expect(
169 + UIManager.dispatchViewManagerCommand,
170 + ).toHaveBeenCalledWith(expect.any(Number), 'myCommand', [10, 20]);
171
172 expect(nativeFabricUIManager.dispatchCommand).not.toBeCalled();
173 });
packages/react-native-renderer/src/__tests__/ReactNativeMount-test.internal.js
+8 -6
@@ -125,11 +125,9 @@ describe('ReactNative', () => {
125 expect(UIManager.dispatchViewManagerCommand).not.toBeCalled();
126 ReactNative.dispatchCommand(viewRef, 'updateCommand', [10, 20]);
127 expect(UIManager.dispatchViewManagerCommand).toHaveBeenCalledTimes(1);
128 - expect(UIManager.dispatchViewManagerCommand).toHaveBeenCalledWith(
129 - expect.any(Number),
130 - 'updateCommand',
131 - [10, 20],
132 - );
128 + expect(
129 + UIManager.dispatchViewManagerCommand,
130 + ).toHaveBeenCalledWith(expect.any(Number), 'updateCommand', [10, 20]);
131 });
132 });
133
@@ -436,7 +434,11 @@ describe('ReactNative', () => {
434 render() {
435 const chars = this.props.chars.split('');
436 return (
439 - <View>{chars.map(text => <View key={text} title={text} />)}</View>
437 + <View>
438 + {chars.map(text => (
439 + <View key={text} title={text} />
440 + ))}
441 + </View>
442 );
443 }
444 }
packages/react-reconciler/src/ReactFiberBeginWork.js
+3 -1
@@ -2384,7 +2384,9 @@ function validateSuspenseListChildren(
2384 if (__DEV__) {
2385 if (
2386 (revealOrder === 'forwards' || revealOrder === 'backwards') &&
2387 - (children !== undefined && children !== null && children !== false)
2387 + children !== undefined &&
2388 + children !== null &&
2389 + children !== false
2390 ) {
2391 if (Array.isArray(children)) {
2392 for (let i = 0; i < children.length; i++) {
packages/react-reconciler/src/ReactFiberCommitWork.js
+2 -5
@@ -297,9 +297,7 @@ function commitBeforeMutationLifeCycles(
297 prevState,
298 );
299 if (__DEV__) {
300 - const didWarnSet = ((didWarnAboutUndefinedSnapshotBeforeUpdate: any): Set<
301 - mixed,
302 - >);
300 + const didWarnSet = ((didWarnAboutUndefinedSnapshotBeforeUpdate: any): Set<mixed>);
301 if (snapshot === undefined && !didWarnSet.has(finishedWork.type)) {
302 didWarnSet.add(finishedWork.type);
303 console.error(
@@ -940,8 +938,7 @@ function commitContainer(finishedWork: Fiber) {
938 const portalOrRoot: {
939 containerInfo: Container,
940 pendingChildren: ChildSet,
943 - } =
944 - finishedWork.stateNode;
941 + } = finishedWork.stateNode;
942 const {containerInfo, pendingChildren} = portalOrRoot;
943 replaceContainerChildren(containerInfo, pendingChildren);
944 return;
packages/react-reconciler/src/ReactFiberCompleteWork.js
+2 -4
@@ -435,8 +435,7 @@ if (supportsMutation) {
435 const portalOrRoot: {
436 containerInfo: Container,
437 pendingChildren: ChildSet,
438 - } =
439 - workInProgress.stateNode;
438 + } = workInProgress.stateNode;
439 const childrenUnchanged = workInProgress.firstEffect === null;
440 if (childrenUnchanged) {
441 // No changes, just reuse the existing instance.
@@ -1201,8 +1200,7 @@ function completeWork(
1200 let fundamentalInstance: ReactFundamentalComponentInstance<
1201 any,
1202 any,
1204 - > | null =
1205 - workInProgress.stateNode;
1203 + > | null = workInProgress.stateNode;
1204
1205 if (fundamentalInstance === null) {
1206 const getInitialState = fundamentalImpl.getInitialState;
packages/react-reconciler/src/ReactFiberHooks.js
+18 -24
@@ -1141,18 +1141,15 @@ function mountDeferredValue<T>(
1141 config: TimeoutConfig | void | null,
1142 ): T {
1143 const [prevValue, setValue] = mountState(value);
1144 - mountEffect(
1145 - () => {
1146 - const previousConfig = ReactCurrentBatchConfig.suspense;
1147 - ReactCurrentBatchConfig.suspense = config === undefined ? null : config;
1148 - try {
1149 - setValue(value);
1150 - } finally {
1151 - ReactCurrentBatchConfig.suspense = previousConfig;
1152 - }
1153 - },
1154 - [value, config],
1155 - );
1144 + mountEffect(() => {
1145 + const previousConfig = ReactCurrentBatchConfig.suspense;
1146 + ReactCurrentBatchConfig.suspense = config === undefined ? null : config;
1147 + try {
1148 + setValue(value);
1149 + } finally {
1150 + ReactCurrentBatchConfig.suspense = previousConfig;
1151 + }
1152 + }, [value, config]);
1153 return prevValue;
1154 }
1155
@@ -1161,18 +1158,15 @@ function updateDeferredValue<T>(
1158 config: TimeoutConfig | void | null,
1159 ): T {
1160 const [prevValue, setValue] = updateState(value);
1164 - updateEffect(
1165 - () => {
1166 - const previousConfig = ReactCurrentBatchConfig.suspense;
1167 - ReactCurrentBatchConfig.suspense = config === undefined ? null : config;
1168 - try {
1169 - setValue(value);
1170 - } finally {
1171 - ReactCurrentBatchConfig.suspense = previousConfig;
1172 - }
1173 - },
1174 - [value, config],
1175 - );
1161 + updateEffect(() => {
1162 + const previousConfig = ReactCurrentBatchConfig.suspense;
1163 + ReactCurrentBatchConfig.suspense = config === undefined ? null : config;
1164 + try {
1165 + setValue(value);
1166 + } finally {
1167 + ReactCurrentBatchConfig.suspense = previousConfig;
1168 + }
1169 + }, [value, config]);
1170 return prevValue;
1171 }
1172
packages/react-reconciler/src/ReactFiberRoot.js
+2 -2
@@ -163,8 +163,8 @@ export function isRootSuspendedAtTime(
163 const lastSuspendedTime = root.lastSuspendedTime;
164 return (
165 firstSuspendedTime !== NoWork &&
166 - (firstSuspendedTime >= expirationTime &&
167 - lastSuspendedTime <= expirationTime)
166 + firstSuspendedTime >= expirationTime &&
167 + lastSuspendedTime <= expirationTime
168 );
169 }
170
packages/react-reconciler/src/ReactFiberWorkLoop.js
+10 -10
@@ -2466,16 +2466,16 @@ function jnd(timeElapsed: number) {
2466 return timeElapsed < 120
2467 ? 120
2468 : timeElapsed < 480
2469 - ? 480
2470 - : timeElapsed < 1080
2471 - ? 1080
2472 - : timeElapsed < 1920
2473 - ? 1920
2474 - : timeElapsed < 3000
2475 - ? 3000
2476 - : timeElapsed < 4320
2477 - ? 4320
2478 - : ceil(timeElapsed / 1960) * 1960;
2469 + ? 480
2470 + : timeElapsed < 1080
2471 + ? 1080
2472 + : timeElapsed < 1920
2473 + ? 1920
2474 + : timeElapsed < 3000
2475 + ? 3000
2476 + : timeElapsed < 4320
2477 + ? 4320
2478 + : ceil(timeElapsed / 1960) * 1960;
2479 }
2480
2481 function computeMsUntilSuspenseLoadingDelay(
packages/react-reconciler/src/__tests__/ReactBatchedMode-test.internal.js
+11 -8
@@ -18,14 +18,17 @@ describe('ReactBlockingMode', () => {
18 ReactCache = require('react-cache');
19 Suspense = React.Suspense;
20
21 - TextResource = ReactCache.unstable_createResource(([text, ms = 0]) => {
22 - return new Promise((resolve, reject) =>
23 - setTimeout(() => {
24 - Scheduler.unstable_yieldValue(`Promise resolved [${text}]`);
25 - resolve(text);
26 - }, ms),
27 - );
28 - }, ([text, ms]) => text);
21 + TextResource = ReactCache.unstable_createResource(
22 + ([text, ms = 0]) => {
23 + return new Promise((resolve, reject) =>
24 + setTimeout(() => {
25 + Scheduler.unstable_yieldValue(`Promise resolved [${text}]`);
26 + resolve(text);
27 + }, ms),
28 + );
29 + },
30 + ([text, ms]) => text,
31 + );
32 });
33
34 function Text(props) {
packages/react-reconciler/src/__tests__/ReactFragment-test.js
+2 -2
@@ -23,8 +23,8 @@ describe('ReactFragment', () => {
23 });
24
25 function div(...children) {
26 - children = children.map(
27 - c => (typeof c === 'string' ? {text: c, hidden: false} : c),
26 + children = children.map(c =>
27 + typeof c === 'string' ? {text: c, hidden: false} : c,
28 );
29 return {type: 'div', children, prop: undefined, hidden: false};
30 }
packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js
+11 -5
@@ -625,10 +625,13 @@ describe('ReactHooks', () => {
625 it('warns if switching from dependencies to no dependencies', () => {
626 const {useMemo} = React;
627 function App({text, hasDeps}) {
628 - const resolvedText = useMemo(() => {
629 - Scheduler.unstable_yieldValue('Compute');
630 - return text.toUpperCase();
631 - }, hasDeps ? null : [text]);
628 + const resolvedText = useMemo(
629 + () => {
630 + Scheduler.unstable_yieldValue('Compute');
631 + return text.toUpperCase();
632 + },
633 + hasDeps ? null : [text],
634 + );
635 return resolvedText;
636 }
637
@@ -1183,7 +1186,10 @@ describe('ReactHooks', () => {
1186 React.useLayoutEffect(() => {});
1187 React.useCallback(() => {});
1188 React.useRef();
1186 - React.useImperativeHandle(() => {}, () => {});
1189 + React.useImperativeHandle(
1190 + () => {},
1191 + () => {},
1192 + );
1193 if (__DEV__) {
1194 React.useDebugValue();
1195 }
packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.internal.js
+49 -67
@@ -63,14 +63,17 @@ describe('ReactHooksWithNoopRenderer', () => {
63 Suspense = React.Suspense;
64 act = ReactNoop.act;
65
66 - TextResource = ReactCache.unstable_createResource(([text, ms = 0]) => {
67 - return new Promise((resolve, reject) =>
68 - setTimeout(() => {
69 - Scheduler.unstable_yieldValue(`Promise resolved [${text}]`);
70 - resolve(text);
71 - }, ms),
72 - );
73 - }, ([text, ms]) => text);
66 + TextResource = ReactCache.unstable_createResource(
67 + ([text, ms = 0]) => {
68 + return new Promise((resolve, reject) =>
69 + setTimeout(() => {
70 + Scheduler.unstable_yieldValue(`Promise resolved [${text}]`);
71 + resolve(text);
72 + }, ms),
73 + );
74 + },
75 + ([text, ms]) => text,
76 + );
77 });
78
79 function span(prop) {
@@ -846,13 +849,10 @@ describe('ReactHooksWithNoopRenderer', () => {
849 it('updates have async priority', () => {
850 function Counter(props) {
851 const [count, updateCount] = useState('(empty)');
849 - useEffect(
850 - () => {
851 - Scheduler.unstable_yieldValue(`Schedule update [${props.count}]`);
852 - updateCount(props.count);
853 - },
854 - [props.count],
855 - );
852 + useEffect(() => {
853 + Scheduler.unstable_yieldValue(`Schedule update [${props.count}]`);
854 + updateCount(props.count);
855 + }, [props.count]);
856 return <Text text={'Count: ' + count} />;
857 }
858 act(() => {
@@ -884,13 +884,10 @@ describe('ReactHooksWithNoopRenderer', () => {
884 it('updates have async priority even if effects are flushed early', () => {
885 function Counter(props) {
886 const [count, updateCount] = useState('(empty)');
887 - useEffect(
888 - () => {
889 - Scheduler.unstable_yieldValue(`Schedule update [${props.count}]`);
890 - updateCount(props.count);
891 - },
892 - [props.count],
893 - );
887 + useEffect(() => {
888 + Scheduler.unstable_yieldValue(`Schedule update [${props.count}]`);
889 + updateCount(props.count);
890 + }, [props.count]);
891 return <Text text={'Count: ' + count} />;
892 }
893 act(() => {
@@ -1038,19 +1035,16 @@ describe('ReactHooksWithNoopRenderer', () => {
1035 () => {
1036 function Counter(props) {
1037 const [count, updateCount] = useState('(empty)');
1041 - useEffect(
1042 - () => {
1043 - // Update multiple times. These should all be batched together in
1044 - // a single render.
1045 - updateCount(props.count);
1046 - updateCount(props.count);
1047 - updateCount(props.count);
1048 - updateCount(props.count);
1049 - updateCount(props.count);
1050 - updateCount(props.count);
1051 - },
1052 - [props.count],
1053 - );
1038 + useEffect(() => {
1039 + // Update multiple times. These should all be batched together in
1040 + // a single render.
1041 + updateCount(props.count);
1042 + updateCount(props.count);
1043 + updateCount(props.count);
1044 + updateCount(props.count);
1045 + updateCount(props.count);
1046 + updateCount(props.count);
1047 + }, [props.count]);
1048 return <Text text={'Count: ' + count} />;
1049 }
1050 act(() => {
@@ -1071,15 +1065,12 @@ describe('ReactHooksWithNoopRenderer', () => {
1065 it('flushSync is not allowed', () => {
1066 function Counter(props) {
1067 const [count, updateCount] = useState('(empty)');
1074 - useEffect(
1075 - () => {
1076 - Scheduler.unstable_yieldValue(`Schedule update [${props.count}]`);
1077 - ReactNoop.flushSync(() => {
1078 - updateCount(props.count);
1079 - });
1080 - },
1081 - [props.count],
1082 - );
1068 + useEffect(() => {
1069 + Scheduler.unstable_yieldValue(`Schedule update [${props.count}]`);
1070 + ReactNoop.flushSync(() => {
1071 + updateCount(props.count);
1072 + });
1073 + }, [props.count]);
1074 return <Text text={'Count: ' + count} />;
1075 }
1076 act(() => {
@@ -1227,15 +1218,12 @@ describe('ReactHooksWithNoopRenderer', () => {
1218 it('skips effect if inputs have not changed', () => {
1219 function Counter(props) {
1220 const text = `${props.label}: ${props.count}`;
1230 - useEffect(
1231 - () => {
1232 - Scheduler.unstable_yieldValue(`Did create [${text}]`);
1233 - return () => {
1234 - Scheduler.unstable_yieldValue(`Did destroy [${text}]`);
1235 - };
1236 - },
1237 - [props.label, props.count],
1238 - );
1221 + useEffect(() => {
1222 + Scheduler.unstable_yieldValue(`Did create [${text}]`);
1223 + return () => {
1224 + Scheduler.unstable_yieldValue(`Did destroy [${text}]`);
1225 + };
1226 + }, [props.label, props.count]);
1227 return <Text text={text} />;
1228 }
1229 act(() => {
@@ -1699,13 +1687,10 @@ describe('ReactHooksWithNoopRenderer', () => {
1687 it('memoizes value by comparing to previous inputs', () => {
1688 function CapitalizedText(props) {
1689 const text = props.text;
1702 - const capitalizedText = useMemo(
1703 - () => {
1704 - Scheduler.unstable_yieldValue(`Capitalize '${text}'`);
1705 - return text.toUpperCase();
1706 - },
1707 - [text],
1708 - );
1690 + const capitalizedText = useMemo(() => {
1691 + Scheduler.unstable_yieldValue(`Capitalize '${text}'`);
1692 + return text.toUpperCase();
1693 + }, [text]);
1694 return <Text text={capitalizedText} />;
1695 }
1696
@@ -2364,13 +2349,10 @@ describe('ReactHooksWithNoopRenderer', () => {
2349 Scheduler.unstable_yieldValue('Reducer: ' + count);
2350 return count;
2351 }, -1);
2367 - useEffect(
2368 - () => {
2369 - Scheduler.unstable_yieldValue('Effect: ' + count);
2370 - dispatch();
2371 - },
2372 - [count],
2373 - );
2352 + useEffect(() => {
2353 + Scheduler.unstable_yieldValue('Effect: ' + count);
2354 + dispatch();
2355 + }, [count]);
2356 Scheduler.unstable_yieldValue('Render: ' + state);
2357 return count;
2358 }
packages/react-reconciler/src/__tests__/ReactIncremental-test.internal.js
+27 -9
@@ -2000,7 +2000,9 @@ describe('ReactIncremental', () => {
2000 }
2001
2002 ReactNoop.render(<Recurse />);
2003 - expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
2003 + expect(() =>
2004 + expect(Scheduler).toFlushWithoutYielding(),
2005 + ).toErrorDev(
2006 'Legacy context API has been detected within a strict-mode tree.\n\n' +
2007 'The old API will be supported in all 16.x releases, but applications ' +
2008 'using it should migrate to the new version.\n\n' +
@@ -2194,7 +2196,9 @@ describe('ReactIncremental', () => {
2196 </IndirectionFn>
2197 </Intl>,
2198 );
2197 - expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
2199 + expect(() =>
2200 + expect(Scheduler).toFlushWithoutYielding(),
2201 + ).toErrorDev(
2202 'Legacy context API has been detected within a strict-mode tree.\n\n' +
2203 'The old API will be supported in all 16.x releases, but applications ' +
2204 'using it should migrate to the new version.\n\n' +
@@ -2288,7 +2292,9 @@ describe('ReactIncremental', () => {
2292 </IndirectionFn>
2293 </Stateful>,
2294 );
2291 - expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
2295 + expect(() =>
2296 + expect(Scheduler).toFlushWithoutYielding(),
2297 + ).toErrorDev(
2298 'Legacy context API has been detected within a strict-mode tree.\n\n' +
2299 'The old API will be supported in all 16.x releases, but applications ' +
2300 'using it should migrate to the new version.\n\n' +
@@ -2359,7 +2365,9 @@ describe('ReactIncremental', () => {
2365
2366 // Init
2367 ReactNoop.render(<Root />);
2362 - expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
2368 + expect(() =>
2369 + expect(Scheduler).toFlushWithoutYielding(),
2370 + ).toErrorDev(
2371 'Legacy context API has been detected within a strict-mode tree.\n\n' +
2372 'The old API will be supported in all 16.x releases, but applications ' +
2373 'using it should migrate to the new version.\n\n' +
@@ -2411,7 +2419,9 @@ describe('ReactIncremental', () => {
2419
2420 // Init
2421 ReactNoop.render(<Root />);
2414 - expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
2422 + expect(() =>
2423 + expect(Scheduler).toFlushWithoutYielding(),
2424 + ).toErrorDev(
2425 'Legacy context API has been detected within a strict-mode tree.\n\n' +
2426 'The old API will be supported in all 16.x releases, but applications ' +
2427 'using it should migrate to the new version.\n\n' +
@@ -2612,7 +2622,9 @@ describe('ReactIncremental', () => {
2622 </TopContextProvider>,
2623 );
2624
2615 - expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
2625 + expect(() =>
2626 + expect(Scheduler).toFlushWithoutYielding(),
2627 + ).toErrorDev(
2628 'Legacy context API has been detected within a strict-mode tree.\n\n' +
2629 'The old API will be supported in all 16.x releases, but applications ' +
2630 'using it should migrate to the new version.\n\n' +
@@ -2676,7 +2688,9 @@ describe('ReactIncremental', () => {
2688 </TopContextProvider>,
2689 );
2690
2679 - expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
2691 + expect(() =>
2692 + expect(Scheduler).toFlushWithoutYielding(),
2693 + ).toErrorDev(
2694 'Legacy context API has been detected within a strict-mode tree.\n\n' +
2695 'The old API will be supported in all 16.x releases, but applications ' +
2696 'using it should migrate to the new version.\n\n' +
@@ -2749,7 +2763,9 @@ describe('ReactIncremental', () => {
2763 </TopContextProvider>,
2764 );
2765
2752 - expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
2766 + expect(() =>
2767 + expect(Scheduler).toFlushWithoutYielding(),
2768 + ).toErrorDev(
2769 'Legacy context API has been detected within a strict-mode tree.\n\n' +
2770 'The old API will be supported in all 16.x releases, but applications ' +
2771 'using it should migrate to the new version.\n\n' +
@@ -2832,7 +2848,9 @@ describe('ReactIncremental', () => {
2848 </TopContextProvider>,
2849 );
2850
2835 - expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
2851 + expect(() =>
2852 + expect(Scheduler).toFlushWithoutYielding(),
2853 + ).toErrorDev(
2854 'Legacy context API has been detected within a strict-mode tree.\n\n' +
2855 'The old API will be supported in all 16.x releases, but applications ' +
2856 'using it should migrate to the new version.\n\n' +
packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js
+6 -2
@@ -1148,7 +1148,9 @@ describe('ReactIncrementalErrorHandling', () => {
1148 <Connector />
1149 </Provider>,
1150 );
1151 - expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
1151 + expect(() =>
1152 + expect(Scheduler).toFlushWithoutYielding(),
1153 + ).toErrorDev(
1154 'Legacy context API has been detected within a strict-mode tree.\n\n' +
1155 'The old API will be supported in all 16.x releases, but ' +
1156 'applications using it should migrate to the new version.\n\n' +
@@ -1252,7 +1254,9 @@ describe('ReactIncrementalErrorHandling', () => {
1254
1255 it('recovers from uncaught reconciler errors', () => {
1256 const InvalidType = undefined;
1255 - expect(() => ReactNoop.render(<InvalidType />)).toErrorDev(
1257 + expect(() =>
1258 + ReactNoop.render(<InvalidType />),
1259 + ).toErrorDev(
1260 'Warning: React.createElement: type is invalid -- expected a string',
1261 {withoutStack: true},
1262 );
packages/react-reconciler/src/__tests__/ReactIncrementalReflection-test.internal.js
+5 -3
@@ -26,8 +26,8 @@ describe('ReactIncrementalReflection', () => {
26 });
27
28 function div(...children) {
29 - children = children.map(
30 - c => (typeof c === 'string' ? {text: c, hidden: false} : c),
29 + children = children.map(c =>
30 + typeof c === 'string' ? {text: c, hidden: false} : c,
31 );
32 return {type: 'div', children, prop: undefined, hidden: false};
33 }
@@ -114,7 +114,9 @@ describe('ReactIncrementalReflection', () => {
114 }
115
116 ReactNoop.render(<Foo mount={true} />);
117 - expect(() => expect(Scheduler).toFlushAndYield(['Component'])).toErrorDev(
117 + expect(() =>
118 + expect(Scheduler).toFlushAndYield(['Component']),
119 + ).toErrorDev(
120 'Using UNSAFE_componentWillMount in strict mode is not recommended',
121 {withoutStack: true},
122 );
packages/react-reconciler/src/__tests__/ReactIncrementalScheduling-test.internal.js
+3 -6
@@ -90,12 +90,9 @@ describe('ReactIncrementalScheduling', () => {
90 it('works on deferred roots in the order they were scheduled', () => {
91 const {useEffect} = React;
92 function Text({text}) {
93 - useEffect(
94 - () => {
95 - Scheduler.unstable_yieldValue(text);
96 - },
97 - [text],
98 - );
93 + useEffect(() => {
94 + Scheduler.unstable_yieldValue(text);
95 + }, [text]);
96 return text;
97 }
98
packages/react-reconciler/src/__tests__/ReactIncrementalSideEffects-test.internal.js
+4 -4
@@ -26,8 +26,8 @@ describe('ReactIncrementalSideEffects', () => {
26 });
27
28 function div(...children) {
29 - children = children.map(
30 - c => (typeof c === 'string' ? {text: c, hidden: false} : c),
29 + children = children.map(c =>
30 + typeof c === 'string' ? {text: c, hidden: false} : c,
31 );
32 return {type: 'div', children, prop: undefined, hidden: false};
33 }
@@ -75,8 +75,8 @@ describe('ReactIncrementalSideEffects', () => {
75 {props.text === 'World'
76 ? [<Bar key="a" text={props.text} />, <div key="b" />]
77 : props.text === 'Hi'
78 - ? [<div key="b" />, <Bar key="a" text={props.text} />]
79 - : null}
78 + ? [<div key="b" />, <Bar key="a" text={props.text} />]
79 + : null}
80 <span prop="test" />
81 </div>
82 );
packages/react-reconciler/src/__tests__/ReactIncrementalUpdates-test.internal.js
+16 -17
@@ -345,7 +345,9 @@ describe('ReactIncrementalUpdates', () => {
345 }
346 }
347 ReactNoop.render(<Foo />);
348 - expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
348 + expect(() =>
349 + expect(Scheduler).toFlushWithoutYielding(),
350 + ).toErrorDev(
351 'Using UNSAFE_componentWillReceiveProps in strict mode is not recommended',
352 {withoutStack: true},
353 );
@@ -663,22 +665,19 @@ describe('ReactIncrementalUpdates', () => {
665 setLog(prevLog => prevLog + msg);
666 };
667
666 - useLayoutEffect(
667 - () => {
668 - Scheduler.unstable_yieldValue('Committed: ' + log);
669 - if (log === 'B') {
670 - // Right after B commits, schedule additional updates.
671 - Scheduler.unstable_runWithPriority(
672 - Scheduler.unstable_UserBlockingPriority,
673 - () => {
674 - pushToLog('C');
675 - },
676 - );
677 - setLog(prevLog => prevLog + 'D');
678 - }
679 - },
680 - [log],
681 - );
668 + useLayoutEffect(() => {
669 + Scheduler.unstable_yieldValue('Committed: ' + log);
670 + if (log === 'B') {
671 + // Right after B commits, schedule additional updates.
672 + Scheduler.unstable_runWithPriority(
673 + Scheduler.unstable_UserBlockingPriority,
674 + () => {
675 + pushToLog('C');
676 + },
677 + );
678 + setLog(prevLog => prevLog + 'D');
679 + }
680 + }, [log]);
681
682 return log;
683 }
packages/react-reconciler/src/__tests__/ReactLazy-test.internal.js
+1 -3
@@ -466,9 +466,7 @@ describe('ReactLazy', () => {
466
467 UNSAFE_componentWillReceiveProps(nextProps) {
468 Scheduler.unstable_yieldValue(
469 - `UNSAFE_componentWillReceiveProps: ${this.props.text} -> ${
470 - nextProps.text
471 - }`,
469 + `UNSAFE_componentWillReceiveProps: ${this.props.text} -> ${nextProps.text}`,
470 );
471 }
472
packages/react-reconciler/src/__tests__/ReactMemo-test.internal.js
+6 -2
@@ -311,7 +311,9 @@ describe('memo', () => {
311 });
312
313 it('warns if the first argument is undefined', () => {
314 - expect(() => memo()).toErrorDev(
314 + expect(() =>
315 + memo(),
316 + ).toErrorDev(
317 'memo: The first argument must be a component. Instead ' +
318 'received: undefined',
319 {withoutStack: true},
@@ -319,7 +321,9 @@ describe('memo', () => {
321 });
322
323 it('warns if the first argument is null', () => {
322 - expect(() => memo(null)).toErrorDev(
324 + expect(() =>
325 + memo(null),
326 + ).toErrorDev(
327 'memo: The first argument must be a component. Instead ' +
328 'received: null',
329 {withoutStack: true},
packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js
+4 -6
@@ -59,7 +59,7 @@ describe('ReactNewContext', () => {
59 }).toErrorDev(
60 observedBits !== undefined
61 ? 'useContext() second argument is reserved for future use in React. ' +
62 - `Passing it is not supported. You passed: ${observedBits}.`
62 + `Passing it is not supported. You passed: ${observedBits}.`
63 : [],
64 );
65 const render = props.children;
@@ -75,7 +75,7 @@ describe('ReactNewContext', () => {
75 }).toErrorDev(
76 observedBits !== undefined
77 ? 'useContext() second argument is reserved for future use in React. ' +
78 - `Passing it is not supported. You passed: ${observedBits}.`
78 + `Passing it is not supported. You passed: ${observedBits}.`
79 : [],
80 );
81 const render = props.children;
@@ -91,7 +91,7 @@ describe('ReactNewContext', () => {
91 }).toErrorDev(
92 observedBits !== undefined
93 ? 'useContext() second argument is reserved for future use in React. ' +
94 - `Passing it is not supported. You passed: ${observedBits}.`
94 + `Passing it is not supported. You passed: ${observedBits}.`
95 : [],
96 );
97 const render = props.children;
@@ -811,9 +811,7 @@ describe('ReactNewContext', () => {
811 Scheduler.unstable_yieldValue('Child');
812 return (
813 <span
814 - prop={`Context: ${this.props.context}, Step: ${
815 - this.state.step
816 - }`}
814 + prop={`Context: ${this.props.context}, Step: ${this.state.step}`}
815 />
816 );
817 }
packages/react-reconciler/src/__tests__/ReactPersistent-test.js
+2 -2
@@ -39,8 +39,8 @@ describe('ReactPersistent', () => {
39 }
40
41 function div(...children) {
42 - children = children.map(
43 - c => (typeof c === 'string' ? {text: c, hidden: false} : c),
42 + children = children.map(c =>
43 + typeof c === 'string' ? {text: c, hidden: false} : c,
44 );
45 return {type: 'div', children, prop: undefined, hidden: false};
46 }
packages/react-reconciler/src/__tests__/ReactSchedulerIntegration-test.internal.js
+1 -2
@@ -403,8 +403,7 @@ describe('ReactSchedulerIntegration', () => {
403 expect(Scheduler).toHaveYielded(['Hidden: B']);
404 expect(root).toMatchRenderedOutput(
405 <>
406 - Visible: B
407 - <div hidden={true}>Hidden: B</div>
406 + Visible: B<div hidden={true}>Hidden: B</div>
407 </>,
408 );
409 });
packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js
+48 -44
@@ -28,46 +28,53 @@ describe('ReactSuspense', () => {
28
29 Suspense = React.Suspense;
30
31 - TextResource = ReactCache.unstable_createResource(([text, ms = 0]) => {
32 - let listeners = null;
33 - let status = 'pending';
34 - let value = null;
35 - return {
36 - then(resolve, reject) {
37 - switch (status) {
38 - case 'pending': {
39 - if (listeners === null) {
40 - listeners = [{resolve, reject}];
41 - setTimeout(() => {
42 - if (textResourceShouldFail) {
43 - Scheduler.unstable_yieldValue(`Promise rejected [${text}]`);
44 - status = 'rejected';
45 - value = new Error('Failed to load: ' + text);
46 - listeners.forEach(listener => listener.reject(value));
47 - } else {
48 - Scheduler.unstable_yieldValue(`Promise resolved [${text}]`);
49 - status = 'resolved';
50 - value = text;
51 - listeners.forEach(listener => listener.resolve(value));
52 - }
53 - }, ms);
54 - } else {
55 - listeners.push({resolve, reject});
31 + TextResource = ReactCache.unstable_createResource(
32 + ([text, ms = 0]) => {
33 + let listeners = null;
34 + let status = 'pending';
35 + let value = null;
36 + return {
37 + then(resolve, reject) {
38 + switch (status) {
39 + case 'pending': {
40 + if (listeners === null) {
41 + listeners = [{resolve, reject}];
42 + setTimeout(() => {
43 + if (textResourceShouldFail) {
44 + Scheduler.unstable_yieldValue(
45 + `Promise rejected [${text}]`,
46 + );
47 + status = 'rejected';
48 + value = new Error('Failed to load: ' + text);
49 + listeners.forEach(listener => listener.reject(value));
50 + } else {
51 + Scheduler.unstable_yieldValue(
52 + `Promise resolved [${text}]`,
53 + );
54 + status = 'resolved';
55 + value = text;
56 + listeners.forEach(listener => listener.resolve(value));
57 + }
58 + }, ms);
59 + } else {
60 + listeners.push({resolve, reject});
61 + }
62 + break;
63 + }
64 + case 'resolved': {
65 + resolve(value);
66 + break;
67 + }
68 + case 'rejected': {
69 + reject(value);
70 + break;
71 }
57 - break;
58 - }
59 - case 'resolved': {
60 - resolve(value);
61 - break;
62 - }
63 - case 'rejected': {
64 - reject(value);
65 - break;
72 }
67 - }
68 - },
69 - };
70 - }, ([text, ms]) => text);
73 + },
74 + };
75 + },
76 + ([text, ms]) => text,
77 + );
78 textResourceShouldFail = false;
79 });
80
@@ -884,12 +891,9 @@ describe('ReactSuspense', () => {
891 function AsyncTextWithEffect(props) {
892 const text = props.text;
893
887 - useLayoutEffect(
888 - () => {
889 - Scheduler.unstable_yieldValue('Did commit: ' + text);
890 - },
891 - [text],
892 - );
894 + useLayoutEffect(() => {
895 + Scheduler.unstable_yieldValue('Did commit: ' + text);
896 + }, [text]);
897
898 try {
899 TextResource.read([props.text, props.ms]);
packages/react-reconciler/src/__tests__/ReactSuspenseFuzz-test.internal.js
+44 -50
@@ -46,32 +46,29 @@ describe('ReactSuspenseFuzz', () => {
46 function Container({children, updates}) {
47 const [step, setStep] = useState(0);
48
49 - useLayoutEffect(
50 - () => {
51 - if (updates !== undefined) {
52 - const cleanUps = new Set();
53 - updates.forEach(({remountAfter}, i) => {
54 - const task = {
55 - label: `Remount children after ${remountAfter}ms`,
56 - };
57 - const timeoutID = setTimeout(() => {
58 - pendingTasks.delete(task);
59 - Scheduler.unstable_yieldValue(task.label);
60 - setStep(i + 1);
61 - }, remountAfter);
62 - pendingTasks.add(task);
63 - cleanUps.add(() => {
64 - pendingTasks.delete(task);
65 - clearTimeout(timeoutID);
66 - });
67 - });
68 - return () => {
69 - cleanUps.forEach(cleanUp => cleanUp());
49 + useLayoutEffect(() => {
50 + if (updates !== undefined) {
51 + const cleanUps = new Set();
52 + updates.forEach(({remountAfter}, i) => {
53 + const task = {
54 + label: `Remount children after ${remountAfter}ms`,
55 };
71 - }
72 - },
73 - [updates],
74 - );
56 + const timeoutID = setTimeout(() => {
57 + pendingTasks.delete(task);
58 + Scheduler.unstable_yieldValue(task.label);
59 + setStep(i + 1);
60 + }, remountAfter);
61 + pendingTasks.add(task);
62 + cleanUps.add(() => {
63 + pendingTasks.delete(task);
64 + clearTimeout(timeoutID);
65 + });
66 + });
67 + return () => {
68 + cleanUps.forEach(cleanUp => cleanUp());
69 + };
70 + }
71 + }, [updates]);
72
73 return <React.Fragment key={step}>{children}</React.Fragment>;
74 }
@@ -79,32 +76,29 @@ describe('ReactSuspenseFuzz', () => {
76 function Text({text, initialDelay = 0, updates}) {
77 const [[step, delay], setStep] = useState([0, initialDelay]);
78
82 - useLayoutEffect(
83 - () => {
84 - if (updates !== undefined) {
85 - const cleanUps = new Set();
86 - updates.forEach(({beginAfter, suspendFor}, i) => {
87 - const task = {
88 - label: `Update ${beginAfter}ms after mount and suspend for ${suspendFor}ms [${text}]`,
89 - };
90 - const timeoutID = setTimeout(() => {
91 - pendingTasks.delete(task);
92 - Scheduler.unstable_yieldValue(task.label);
93 - setStep([i + 1, suspendFor]);
94 - }, beginAfter);
95 - pendingTasks.add(task);
96 - cleanUps.add(() => {
97 - pendingTasks.delete(task);
98 - clearTimeout(timeoutID);
99 - });
100 - });
101 - return () => {
102 - cleanUps.forEach(cleanUp => cleanUp());
79 + useLayoutEffect(() => {
80 + if (updates !== undefined) {
81 + const cleanUps = new Set();
82 + updates.forEach(({beginAfter, suspendFor}, i) => {
83 + const task = {
84 + label: `Update ${beginAfter}ms after mount and suspend for ${suspendFor}ms [${text}]`,
85 };
104 - }
105 - },
106 - [updates],
107 - );
86 + const timeoutID = setTimeout(() => {
87 + pendingTasks.delete(task);
88 + Scheduler.unstable_yieldValue(task.label);
89 + setStep([i + 1, suspendFor]);
90 + }, beginAfter);
91 + pendingTasks.add(task);
92 + cleanUps.add(() => {
93 + pendingTasks.delete(task);
94 + clearTimeout(timeoutID);
95 + });
96 + });
97 + return () => {
98 + cleanUps.forEach(cleanUp => cleanUp());
99 + };
100 + }
101 + }, [updates]);
102
103 const fullText = `${text}:${step}`;
104
packages/react-reconciler/src/__tests__/ReactSuspenseList-test.internal.js
+81 -10
@@ -925,7 +925,14 @@ describe('ReactSuspenseList', () => {
925 await B.resolve();
926 await D.resolve();
927
928 - ReactNoop.render(<Foo items={[['B', B], ['D', D]]} />);
928 + ReactNoop.render(
929 + <Foo
930 + items={[
931 + ['B', B],
932 + ['D', D],
933 + ]}
934 + />,
935 + );
936
937 expect(Scheduler).toFlushAndYield(['B', 'D']);
938
@@ -939,7 +946,14 @@ describe('ReactSuspenseList', () => {
946 // Insert items in the beginning, middle and end.
947 ReactNoop.render(
948 <Foo
942 - items={[['A', A], ['B', B], ['C', C], ['D', D], ['E', E], ['F', F]]}
949 + items={[
950 + ['A', A],
951 + ['B', B],
952 + ['C', C],
953 + ['D', D],
954 + ['E', E],
955 + ['F', F],
956 + ]}
957 />,
958 );
959
@@ -1021,7 +1035,15 @@ describe('ReactSuspenseList', () => {
1035 await F.resolve();
1036
1037 // We can also delete some items.
1024 - ReactNoop.render(<Foo items={[['D', D], ['E', E], ['F', F]]} />);
1038 + ReactNoop.render(
1039 + <Foo
1040 + items={[
1041 + ['D', D],
1042 + ['E', E],
1043 + ['F', F],
1044 + ]}
1045 + />,
1046 + );
1047
1048 expect(Scheduler).toFlushAndYield(['D', 'E', 'F']);
1049
@@ -1093,7 +1115,14 @@ describe('ReactSuspenseList', () => {
1115 // Update items in the beginning, middle and end to start suspending.
1116 ReactNoop.render(
1117 <Foo
1096 - items={[['A', A], ['B', B], ['C', Cs], ['D', D], ['E', Es], ['F', F]]}
1118 + items={[
1119 + ['A', A],
1120 + ['B', B],
1121 + ['C', Cs],
1122 + ['D', D],
1123 + ['E', Es],
1124 + ['F', F],
1125 + ]}
1126 />,
1127 );
1128
@@ -1468,7 +1497,14 @@ describe('ReactSuspenseList', () => {
1497 );
1498 }
1499
1471 - ReactNoop.render(<Foo items={[['A', A], ['D', D]]} />);
1500 + ReactNoop.render(
1501 + <Foo
1502 + items={[
1503 + ['A', A],
1504 + ['D', D],
1505 + ]}
1506 + />,
1507 + );
1508
1509 await A.resolve();
1510 await D.resolve();
@@ -1486,7 +1522,14 @@ describe('ReactSuspenseList', () => {
1522 // For the second render, we're going to insert items in the middle and end.
1523 ReactNoop.render(
1524 <Foo
1489 - items={[['A', A], ['B', B], ['C', C], ['D', D], ['E', E], ['F', F]]}
1525 + items={[
1526 + ['A', A],
1527 + ['B', B],
1528 + ['C', C],
1529 + ['D', D],
1530 + ['E', E],
1531 + ['F', F],
1532 + ]}
1533 />,
1534 );
1535
@@ -1596,7 +1639,14 @@ describe('ReactSuspenseList', () => {
1639 );
1640 }
1641
1599 - ReactNoop.render(<Foo items={[['C', C], ['F', F]]} />);
1642 + ReactNoop.render(
1643 + <Foo
1644 + items={[
1645 + ['C', C],
1646 + ['F', F],
1647 + ]}
1648 + />,
1649 + );
1650
1651 await C.resolve();
1652 await F.resolve();
@@ -1614,7 +1664,14 @@ describe('ReactSuspenseList', () => {
1664 // For the second render, we're going to insert items in the middle and end.
1665 ReactNoop.render(
1666 <Foo
1617 - items={[['A', A], ['B', B], ['C', C], ['D', D], ['E', E], ['F', F]]}
1667 + items={[
1668 + ['A', A],
1669 + ['B', B],
1670 + ['C', C],
1671 + ['D', D],
1672 + ['E', E],
1673 + ['F', F],
1674 + ]}
1675 />,
1676 );
1677
@@ -1733,7 +1790,14 @@ describe('ReactSuspenseList', () => {
1790 );
1791 }
1792
1736 - ReactNoop.render(<Foo items={[['A', A], ['D', SyncD]]} />);
1793 + ReactNoop.render(
1794 + <Foo
1795 + items={[
1796 + ['A', A],
1797 + ['D', SyncD],
1798 + ]}
1799 + />,
1800 + );
1801
1802 await A.resolve();
1803
@@ -1751,7 +1815,14 @@ describe('ReactSuspenseList', () => {
1815 // Note that D now suspends even though it didn't in the first pass.
1816 ReactNoop.render(
1817 <Foo
1754 - items={[['A', A], ['B', B], ['C', C], ['D', D], ['E', E], ['F', F]]}
1818 + items={[
1819 + ['A', A],
1820 + ['B', B],
1821 + ['C', C],
1822 + ['D', D],
1823 + ['E', E],
1824 + ['F', F],
1825 + ]}
1826 />,
1827 );
1828
packages/react-reconciler/src/__tests__/ReactSuspensePlaceholder-test.internal.js
+45 -38
@@ -34,46 +34,53 @@ describe('ReactSuspensePlaceholder', () => {
34 Profiler = React.Profiler;
35 Suspense = React.Suspense;
36
37 - TextResource = ReactCache.unstable_createResource(([text, ms = 0]) => {
38 - let listeners = null;
39 - let status = 'pending';
40 - let value = null;
41 - return {
42 - then(resolve, reject) {
43 - switch (status) {
44 - case 'pending': {
45 - if (listeners === null) {
46 - listeners = [{resolve, reject}];
47 - setTimeout(() => {
48 - if (textResourceShouldFail) {
49 - Scheduler.unstable_yieldValue(`Promise rejected [${text}]`);
50 - status = 'rejected';
51 - value = new Error('Failed to load: ' + text);
52 - listeners.forEach(listener => listener.reject(value));
53 - } else {
54 - Scheduler.unstable_yieldValue(`Promise resolved [${text}]`);
55 - status = 'resolved';
56 - value = text;
57 - listeners.forEach(listener => listener.resolve(value));
58 - }
59 - }, ms);
60 - } else {
61 - listeners.push({resolve, reject});
37 + TextResource = ReactCache.unstable_createResource(
38 + ([text, ms = 0]) => {
39 + let listeners = null;
40 + let status = 'pending';
41 + let value = null;
42 + return {
43 + then(resolve, reject) {
44 + switch (status) {
45 + case 'pending': {
46 + if (listeners === null) {
47 + listeners = [{resolve, reject}];
48 + setTimeout(() => {
49 + if (textResourceShouldFail) {
50 + Scheduler.unstable_yieldValue(
51 + `Promise rejected [${text}]`,
52 + );
53 + status = 'rejected';
54 + value = new Error('Failed to load: ' + text);
55 + listeners.forEach(listener => listener.reject(value));
56 + } else {
57 + Scheduler.unstable_yieldValue(
58 + `Promise resolved [${text}]`,
59 + );
60 + status = 'resolved';
61 + value = text;
62 + listeners.forEach(listener => listener.resolve(value));
63 + }
64 + }, ms);
65 + } else {
66 + listeners.push({resolve, reject});
67 + }
68 + break;
69 + }
70 + case 'resolved': {
71 + resolve(value);
72 + break;
73 + }
74 + case 'rejected': {
75 + reject(value);
76 + break;
77 }
63 - break;
64 - }
65 - case 'resolved': {
66 - resolve(value);
67 - break;
68 - }
69 - case 'rejected': {
70 - reject(value);
71 - break;
78 }
73 - }
74 - },
75 - };
76 - }, ([text, ms]) => text);
79 + },
80 + };
81 + },
82 + ([text, ms]) => text,
83 + );
84 textResourceShouldFail = false;
85 });
86
packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.internal.js
+46 -54
@@ -28,19 +28,22 @@ describe('ReactSuspenseWithNoopRenderer', () => {
28 ReactCache = require('react-cache');
29 Suspense = React.Suspense;
30
31 - TextResource = ReactCache.unstable_createResource(([text, ms = 0]) => {
32 - return new Promise((resolve, reject) =>
33 - setTimeout(() => {
34 - if (textResourceShouldFail) {
35 - Scheduler.unstable_yieldValue(`Promise rejected [${text}]`);
36 - reject(new Error('Failed to load: ' + text));
37 - } else {
38 - Scheduler.unstable_yieldValue(`Promise resolved [${text}]`);
39 - resolve(text);
40 - }
41 - }, ms),
42 - );
43 - }, ([text, ms]) => text);
31 + TextResource = ReactCache.unstable_createResource(
32 + ([text, ms = 0]) => {
33 + return new Promise((resolve, reject) =>
34 + setTimeout(() => {
35 + if (textResourceShouldFail) {
36 + Scheduler.unstable_yieldValue(`Promise rejected [${text}]`);
37 + reject(new Error('Failed to load: ' + text));
38 + } else {
39 + Scheduler.unstable_yieldValue(`Promise resolved [${text}]`);
40 + resolve(text);
41 + }
42 + }, ms),
43 + );
44 + },
45 + ([text, ms]) => text,
46 + );
47 textResourceShouldFail = false;
48 });
49
@@ -1514,50 +1517,38 @@ describe('ReactSuspenseWithNoopRenderer', () => {
1517
1518 it('does not call lifecycles of a suspended component (hooks)', async () => {
1519 function TextWithLifecycle(props) {
1517 - React.useLayoutEffect(
1518 - () => {
1519 - Scheduler.unstable_yieldValue(`Layout Effect [${props.text}]`);
1520 - return () => {
1521 - Scheduler.unstable_yieldValue(
1522 - `Destroy Layout Effect [${props.text}]`,
1523 - );
1524 - };
1525 - },
1526 - [props.text],
1527 - );
1528 - React.useEffect(
1529 - () => {
1530 - Scheduler.unstable_yieldValue(`Effect [${props.text}]`);
1531 - return () => {
1532 - Scheduler.unstable_yieldValue(`Destroy Effect [${props.text}]`);
1533 - };
1534 - },
1535 - [props.text],
1536 - );
1520 + React.useLayoutEffect(() => {
1521 + Scheduler.unstable_yieldValue(`Layout Effect [${props.text}]`);
1522 + return () => {
1523 + Scheduler.unstable_yieldValue(
1524 + `Destroy Layout Effect [${props.text}]`,
1525 + );
1526 + };
1527 + }, [props.text]);
1528 + React.useEffect(() => {
1529 + Scheduler.unstable_yieldValue(`Effect [${props.text}]`);
1530 + return () => {
1531 + Scheduler.unstable_yieldValue(`Destroy Effect [${props.text}]`);
1532 + };
1533 + }, [props.text]);
1534 return <Text {...props} />;
1535 }
1536
1537 function AsyncTextWithLifecycle(props) {
1541 - React.useLayoutEffect(
1542 - () => {
1543 - Scheduler.unstable_yieldValue(`Layout Effect [${props.text}]`);
1544 - return () => {
1545 - Scheduler.unstable_yieldValue(
1546 - `Destroy Layout Effect [${props.text}]`,
1547 - );
1548 - };
1549 - },
1550 - [props.text],
1551 - );
1552 - React.useEffect(
1553 - () => {
1554 - Scheduler.unstable_yieldValue(`Effect [${props.text}]`);
1555 - return () => {
1556 - Scheduler.unstable_yieldValue(`Destroy Effect [${props.text}]`);
1557 - };
1558 - },
1559 - [props.text],
1560 - );
1538 + React.useLayoutEffect(() => {
1539 + Scheduler.unstable_yieldValue(`Layout Effect [${props.text}]`);
1540 + return () => {
1541 + Scheduler.unstable_yieldValue(
1542 + `Destroy Layout Effect [${props.text}]`,
1543 + );
1544 + };
1545 + }, [props.text]);
1546 + React.useEffect(() => {
1547 + Scheduler.unstable_yieldValue(`Effect [${props.text}]`);
1548 + return () => {
1549 + Scheduler.unstable_yieldValue(`Destroy Effect [${props.text}]`);
1550 + };
1551 + }, [props.text]);
1552 const text = props.text;
1553 const ms = props.ms;
1554 try {
@@ -2896,7 +2887,8 @@ describe('ReactSuspenseWithNoopRenderer', () => {
2887 expect(ReactNoop).toMatchRenderedOutput(
2888 <>
2889 <div hidden={true}>
2899 - <span prop="A" />Offscreen
2890 + <span prop="A" />
2891 + Offscreen
2892 </div>
2893 <span prop="A" />
2894 </>,
packages/react-refresh/src/__tests__/ReactFresh-test.js
+4 -2
@@ -1817,12 +1817,14 @@ describe('ReactFresh', () => {
1817 <span />
1818 Hello
1819 <span />
1820 - </HelloV1>,
1820 + </HelloV1>
1821 + ,
1822 <HelloV1>
1823 <>
1824 <HelloV1 />
1825 </>
1825 - </HelloV1>,
1826 + </HelloV1>
1827 + ,
1828 </div>,
1829 <HelloV1>
1830 <HelloV1>
packages/react-test-renderer/src/ReactShallowRenderer.js
+9 -7
@@ -295,9 +295,10 @@ class ReactShallowRenderer {
295 first: null,
296 dispatch: null,
297 });
298 - const dispatch: Dispatch<
299 - A,
300 - > = (queue.dispatch = (this._dispatchAction.bind(this, queue): any));
298 + const dispatch: Dispatch<A> = (queue.dispatch = (this._dispatchAction.bind(
299 + this,
300 + queue,
301 + ): any));
302 return [workInProgressHook.memoizedState, dispatch];
303 }
304 };
@@ -529,7 +530,7 @@ class ReactShallowRenderer {
530 'ReactShallowRenderer render(): Invalid component element.%s',
531 typeof element === 'function'
532 ? ' Instead of passing a component class, make sure to instantiate ' +
532 - 'it by passing it to React.createElement.'
533 + 'it by passing it to React.createElement.'
534 : '',
535 );
536 element = ((element: any): ReactElement);
@@ -543,14 +544,15 @@ class ReactShallowRenderer {
544 );
545 invariant(
546 isForwardRef(element) ||
546 - (typeof element.type === 'function' || isMemo(element)),
547 + typeof element.type === 'function' ||
548 + isMemo(element),
549 'ReactShallowRenderer render(): Shallow rendering works only with custom ' +
550 'components, but the provided element type was `%s`.',
551 Array.isArray(element.type)
552 ? 'array'
553 : element.type === null
552 - ? 'null'
553 - : typeof element.type,
554 + ? 'null'
555 + : typeof element.type,
556 );
557
558 if (this._rendering) {
packages/react/src/ReactHooks.js
+2 -2
@@ -45,8 +45,8 @@ export function useContext<T>(
45 unstable_observedBits,
46 typeof unstable_observedBits === 'number' && Array.isArray(arguments[2])
47 ? '\n\nDid you call array.map(useContext)? ' +
48 - 'Calling Hooks inside a loop is not supported. ' +
49 - 'Learn more at https://fb.me/rules-of-hooks'
48 + 'Calling Hooks inside a loop is not supported. ' +
49 + 'Learn more at https://fb.me/rules-of-hooks'
50 : '',
51 );
52 }
packages/react/src/__tests__/ReactDOMTracing-test.internal.js
+19 -25
@@ -73,17 +73,14 @@ describe('ReactDOMTracing', () => {
73 const Child = () => {
74 const [didMount, setDidMount] = React.useState(false);
75 Scheduler.unstable_yieldValue('Child');
76 - React.useEffect(
77 - () => {
78 - if (didMount) {
79 - Scheduler.unstable_yieldValue('Child:update');
80 - } else {
81 - Scheduler.unstable_yieldValue('Child:mount');
82 - setDidMount(true);
83 - }
84 - },
85 - [didMount],
86 - );
76 + React.useEffect(() => {
77 + if (didMount) {
78 + Scheduler.unstable_yieldValue('Child:update');
79 + } else {
80 + Scheduler.unstable_yieldValue('Child:mount');
81 + setDidMount(true);
82 + }
83 + }, [didMount]);
84 return <div />;
85 };
86
@@ -219,20 +216,17 @@ describe('ReactDOMTracing', () => {
216 const Child = () => {
217 const [didMount, setDidMount] = React.useState(false);
218 Scheduler.unstable_yieldValue('Child');
222 - React.useLayoutEffect(
223 - () => {
224 - if (didMount) {
225 - Scheduler.unstable_yieldValue('Child:update');
226 - } else {
227 - Scheduler.unstable_yieldValue('Child:mount');
228 - Scheduler.unstable_runWithPriority(
229 - Scheduler.unstable_IdlePriority,
230 - () => setDidMount(true),
231 - );
232 - }
233 - },
234 - [didMount],
235 - );
219 + React.useLayoutEffect(() => {
220 + if (didMount) {
221 + Scheduler.unstable_yieldValue('Child:update');
222 + } else {
223 + Scheduler.unstable_yieldValue('Child:mount');
224 + Scheduler.unstable_runWithPriority(
225 + Scheduler.unstable_IdlePriority,
226 + () => setDidMount(true),
227 + );
228 + }
229 + }, [didMount]);
230 return <div />;
231 };
232
packages/react/src/__tests__/ReactES6Class-test.js
+6 -2
@@ -521,11 +521,15 @@ describe('ReactES6Class', () => {
521
522 it('should throw AND warn when trying to access classic APIs', () => {
523 const instance = test(<Inner name="foo" />, 'DIV', 'foo');
524 - expect(() => expect(() => instance.replaceState({})).toThrow()).toWarnDev(
524 + expect(() =>
525 + expect(() => instance.replaceState({})).toThrow(),
526 + ).toWarnDev(
527 'replaceState(...) is deprecated in plain JavaScript React classes',
528 {withoutStack: true},
529 );
528 - expect(() => expect(() => instance.isMounted()).toThrow()).toWarnDev(
530 + expect(() =>
531 + expect(() => instance.isMounted()).toThrow(),
532 + ).toWarnDev(
533 'isMounted(...) is deprecated in plain JavaScript React classes',
534 {withoutStack: true},
535 );
packages/react/src/__tests__/ReactElement-test.js
+4 -2
@@ -42,7 +42,7 @@ describe('ReactElement', () => {
42 });
43
44 it('uses the fallback value when in an environment without Symbol', () => {
45 - expect(<div />.$$typeof).toBe(0xeac7);
45 + expect((<div />).$$typeof).toBe(0xeac7);
46 });
47
48 it('returns a complete element according to spec', () => {
@@ -85,7 +85,9 @@ describe('ReactElement', () => {
85
86 it('should warn when `key` is being accessed on a host element', () => {
87 const element = <div key="3" />;
88 - expect(() => void element.props.key).toErrorDev(
88 + expect(
89 + () => void element.props.key,
90 + ).toErrorDev(
91 'div: `key` is not a prop. Trying to access it will result ' +
92 'in `undefined` being returned. If you need to access the same ' +
93 'value within the child component, you should pass it as a different ' +
packages/react/src/__tests__/ReactElementJSX-test.internal.js
+3 -1
@@ -228,7 +228,9 @@ describe('ReactElement.jsx', () => {
228
229 it('should warn when `key` is being accessed on a host element', () => {
230 const element = React.jsxs('div', {}, '3');
231 - expect(() => void element.props.key).toErrorDev(
231 + expect(
232 + () => void element.props.key,
233 + ).toErrorDev(
234 'div: `key` is not a prop. Trying to access it will result ' +
235 'in `undefined` being returned. If you need to access the same ' +
236 'value within the child component, you should pass it as a different ' +
packages/react/src/__tests__/ReactElementValidator-test.internal.js
+6 -4
@@ -439,7 +439,9 @@ describe('ReactElementValidator', () => {
439 }
440
441 let TestFactory = React.createFactory(TestComponent);
442 - expect(() => TestFactory.type).toWarnDev(
442 + expect(
443 + () => TestFactory.type,
444 + ).toWarnDev(
445 'Warning: Factory.type is deprecated. Access the class directly before ' +
446 'passing it to createFactory.',
447 {withoutStack: true},
@@ -489,7 +491,7 @@ describe('ReactElementValidator', () => {
491 // shouldn't blow up either.
492
493 const child = {
492 - $$typeof: <div />.$$typeof,
494 + $$typeof: (<div />).$$typeof,
495 type: 'span',
496 key: null,
497 ref: null,
@@ -497,13 +499,13 @@ describe('ReactElementValidator', () => {
499 _owner: null,
500 };
501
500 - void <div>{[child]}</div>;
502 + void (<div>{[child]}</div>);
503 });
504
505 it('does not blow up on key warning with undefined type', () => {
506 const Foo = undefined;
507 expect(() => {
506 - void <Foo>{[<div />]}</Foo>;
508 + void (<Foo>{[<div />]}</Foo>);
509 }).toErrorDev(
510 'Warning: React.createElement: type is invalid -- expected a string ' +
511 '(for built-in components) or a class/function (for composite ' +
packages/react/src/__tests__/ReactJSXElementValidator-test.js
+11 -5
@@ -143,7 +143,7 @@ describe('ReactJSXElementValidator', () => {
143 });
144
145 it('does not warn when the child array contains non-elements', () => {
146 - void <Component>{[{}, {}]}</Component>;
146 + void (<Component>{[{}, {}]}</Component>);
147 });
148
149 it('should give context for PropType errors in nested components.', () => {
@@ -210,7 +210,9 @@ describe('ReactJSXElementValidator', () => {
210 const Null = null;
211 const True = true;
212 const Div = 'div';
213 - expect(() => void <Undefined />).toErrorDev(
213 + expect(
214 + () => void (<Undefined />),
215 + ).toErrorDev(
216 'Warning: React.createElement: type is invalid -- expected a string ' +
217 '(for built-in components) or a class/function (for composite ' +
218 'components) but got: undefined. You likely forgot to export your ' +
@@ -219,14 +221,18 @@ describe('ReactJSXElementValidator', () => {
221 '\n\nCheck your code at **.',
222 {withoutStack: true},
223 );
222 - expect(() => void <Null />).toErrorDev(
224 + expect(
225 + () => void (<Null />),
226 + ).toErrorDev(
227 'Warning: React.createElement: type is invalid -- expected a string ' +
228 '(for built-in components) or a class/function (for composite ' +
229 'components) but got: null.' +
230 '\n\nCheck your code at **.',
231 {withoutStack: true},
232 );
229 - expect(() => void <True />).toErrorDev(
233 + expect(
234 + () => void (<True />),
235 + ).toErrorDev(
236 'Warning: React.createElement: type is invalid -- expected a string ' +
237 '(for built-in components) or a class/function (for composite ' +
238 'components) but got: boolean.' +
@@ -234,7 +240,7 @@ describe('ReactJSXElementValidator', () => {
240 {withoutStack: true},
241 );
242 // No error expected
237 - void <Div />;
243 + void (<Div />);
244 });
245
246 it('should check default prop values', () => {
packages/react/src/__tests__/ReactProfiler-test.internal.js
+19 -13
@@ -65,15 +65,18 @@ function loadModules({
65
66 resourcePromise = null;
67
68 - TextResource = ReactCache.unstable_createResource(([text, ms = 0]) => {
69 - resourcePromise = new Promise((resolve, reject) =>
70 - setTimeout(() => {
71 - Scheduler.unstable_yieldValue(`Promise resolved [${text}]`);
72 - resolve(text);
73 - }, ms),
74 - );
75 - return resourcePromise;
76 - }, ([text, ms]) => text);
68 + TextResource = ReactCache.unstable_createResource(
69 + ([text, ms = 0]) => {
70 + resourcePromise = new Promise((resolve, reject) =>
71 + setTimeout(() => {
72 + Scheduler.unstable_yieldValue(`Promise resolved [${text}]`);
73 + resolve(text);
74 + }, ms),
75 + );
76 + return resourcePromise;
77 + },
78 + ([text, ms]) => text,
79 + );
80
81 AsyncText = ({ms, text}) => {
82 try {
@@ -297,10 +300,13 @@ describe('Profiler', () => {
300 it('does not report work done on a sibling', () => {
301 const callback = jest.fn();
302
300 - const DoesNotUpdate = React.memo(function DoesNotUpdateInner() {
301 - Scheduler.unstable_advanceTime(10);
302 - return null;
303 - }, () => true);
303 + const DoesNotUpdate = React.memo(
304 + function DoesNotUpdateInner() {
305 + Scheduler.unstable_advanceTime(10);
306 + return null;
307 + },
308 + () => true,
309 + );
310
311 let updateProfilerSibling;
312
packages/react/src/__tests__/ReactStrictMode-test.js
+9 -3
@@ -535,13 +535,17 @@ Please update the following components: Parent`,
535 const container = document.createElement('div');
536 const root = ReactDOM.createRoot(container);
537 root.render(<AsyncRoot foo={true} />);
538 - expect(() => Scheduler.unstable_flushAll()).toErrorDev(
538 + expect(() =>
539 + Scheduler.unstable_flushAll(),
540 + ).toErrorDev(
541 'Using UNSAFE_componentWillMount in strict mode is not recommended',
542 {withoutStack: true},
543 );
544
545 root.render(<AsyncRoot foo={false} />);
544 - expect(() => Scheduler.unstable_flushAll()).toErrorDev(
546 + expect(() =>
547 + Scheduler.unstable_flushAll(),
548 + ).toErrorDev(
549 'Using UNSAFE_componentWillMount in strict mode is not recommended',
550 {withoutStack: true},
551 );
@@ -592,7 +596,9 @@ Please update the following components: Parent`,
596
597 const container = document.createElement('div');
598
595 - expect(() => ReactDOM.render(<SyncRoot />, container)).toErrorDev(
599 + expect(() =>
600 + ReactDOM.render(<SyncRoot />, container),
601 + ).toErrorDev(
602 'Using UNSAFE_componentWillReceiveProps in strict mode is not recommended',
603 {withoutStack: true},
604 );
packages/react/src/__tests__/createReactClassIntegration-test.internal.js
+6 -5
@@ -50,10 +50,9 @@ describe('create-react-class-integration', () => {
50 render: () => null,
51 });
52
53 - expect(() => ReactNative.render(<View />, 1)).toWarnDev(
54 - 'componentWillMount has been renamed',
55 - {withoutStack: true},
56 - );
53 + expect(() =>
54 + ReactNative.render(<View />, 1),
55 + ).toWarnDev('componentWillMount has been renamed', {withoutStack: true});
56 });
57
58 it('should warn if users specify their own legacy componentWillReceiveProps', () => {
@@ -66,7 +65,9 @@ describe('create-react-class-integration', () => {
65
66 expect(() => ReactNative.render(<View />, 1)).toWarnDev(
67 'componentWillReceiveProps has been renamed',
69 - {withoutStack: true},
68 + {
69 + withoutStack: true,
70 + },
71 );
72 });
73 });
packages/react/src/__tests__/createReactClassIntegration-test.js
+6 -2
@@ -361,7 +361,9 @@ describe('create-react-class-integration', () => {
361 },
362 });
363
364 - expect(() => expect(() => Component()).toThrow()).toErrorDev(
364 + expect(() =>
365 + expect(() => Component()).toThrow(),
366 + ).toErrorDev(
367 'Warning: Something is calling a React component directly. Use a ' +
368 'factory or JSX instead. See: https://fb.me/react-legacyfactory',
369 {withoutStack: true},
@@ -717,7 +719,9 @@ describe('create-react-class-integration', () => {
719
720 const container = document.createElement('div');
721
720 - expect(() => ReactDOM.render(<Component />, container)).toErrorDev(
722 + expect(() =>
723 + ReactDOM.render(<Component />, container),
724 + ).toErrorDev(
725 'Warning: MyComponent: isMounted is deprecated. Instead, make sure to ' +
726 'clean up subscriptions and pending requests in componentWillUnmount ' +
727 'to prevent memory leaks.',
packages/react/src/__tests__/forwardRef-test.js
+24 -8
@@ -126,22 +126,30 @@ describe('forwardRef', () => {
126 });
127
128 it('should warn if not provided a callback during creation', () => {
129 - expect(() => React.forwardRef(undefined)).toErrorDev(
129 + expect(() =>
130 + React.forwardRef(undefined),
131 + ).toErrorDev(
132 'forwardRef requires a render function but was given undefined.',
133 {withoutStack: true},
134 );
135 expect(() => React.forwardRef(null)).toErrorDev(
136 'forwardRef requires a render function but was given null.',
135 - {withoutStack: true},
137 + {
138 + withoutStack: true,
139 + },
140 );
137 - expect(() => React.forwardRef('foo')).toErrorDev(
141 + expect(() =>
142 + React.forwardRef('foo'),
143 + ).toErrorDev(
144 'forwardRef requires a render function but was given string.',
145 {withoutStack: true},
146 );
147 });
148
149 it('should warn if no render function is provided', () => {
144 - expect(React.forwardRef).toErrorDev(
150 + expect(
151 + React.forwardRef,
152 + ).toErrorDev(
153 'forwardRef requires a render function but was given undefined.',
154 {withoutStack: true},
155 );
@@ -158,12 +166,16 @@ describe('forwardRef', () => {
166 }
167 renderWithDefaultProps.defaultProps = {};
168
161 - expect(() => React.forwardRef(renderWithPropTypes)).toErrorDev(
169 + expect(() =>
170 + React.forwardRef(renderWithPropTypes),
171 + ).toErrorDev(
172 'forwardRef render functions do not support propTypes or defaultProps. ' +
173 'Did you accidentally pass a React component?',
174 {withoutStack: true},
175 );
166 - expect(() => React.forwardRef(renderWithDefaultProps)).toErrorDev(
176 + expect(() =>
177 + React.forwardRef(renderWithDefaultProps),
178 + ).toErrorDev(
179 'forwardRef render functions do not support propTypes or defaultProps. ' +
180 'Did you accidentally pass a React component?',
181 {withoutStack: true},
@@ -179,7 +191,9 @@ describe('forwardRef', () => {
191 it('should warn if the render function provided does not use the forwarded ref parameter', () => {
192 const arityOfOne = props => <div {...props} />;
193
182 - expect(() => React.forwardRef(arityOfOne)).toErrorDev(
194 + expect(() =>
195 + React.forwardRef(arityOfOne),
196 + ).toErrorDev(
197 'forwardRef render functions accept exactly two parameters: props and ref. ' +
198 'Did you forget to use the ref parameter?',
199 {withoutStack: true},
@@ -194,7 +208,9 @@ describe('forwardRef', () => {
208 it('should warn if the render function provided expects to use more than two parameters', () => {
209 const arityOfThree = (props, ref, x) => <div {...props} ref={ref} x={x} />;
210
197 - expect(() => React.forwardRef(arityOfThree)).toErrorDev(
211 + expect(() =>
212 + React.forwardRef(arityOfThree),
213 + ).toErrorDev(
214 'forwardRef render functions accept exactly two parameters: props and ref. ' +
215 'Any additional parameter will be undefined.',
216 {withoutStack: true},
packages/scheduler/npm/umd/scheduler-tracing.development.js
+2 -2
@@ -14,8 +14,8 @@
14 typeof exports === 'object' && typeof module !== 'undefined'
15 ? (module.exports = factory(require('react')))
16 : typeof define === 'function' && define.amd // eslint-disable-line no-undef
17 - ? define(['react'], factory) // eslint-disable-line no-undef
18 - : (global.SchedulerTracing = factory(global));
17 + ? define(['react'], factory) // eslint-disable-line no-undef
18 + : (global.SchedulerTracing = factory(global));
19 })(this, function(global) {
20 function unstable_clear() {
21 return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTracing.unstable_clear.apply(
packages/scheduler/npm/umd/scheduler-tracing.production.min.js
+2 -2
@@ -14,8 +14,8 @@
14 typeof exports === 'object' && typeof module !== 'undefined'
15 ? (module.exports = factory(require('react')))
16 : typeof define === 'function' && define.amd // eslint-disable-line no-undef
17 - ? define(['react'], factory) // eslint-disable-line no-undef
18 - : (global.SchedulerTracing = factory(global));
17 + ? define(['react'], factory) // eslint-disable-line no-undef
18 + : (global.SchedulerTracing = factory(global));
19 })(this, function(global) {
20 function unstable_clear() {
21 return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTracing.unstable_clear.apply(
packages/scheduler/npm/umd/scheduler-tracing.profiling.min.js
+2 -2
@@ -14,8 +14,8 @@
14 typeof exports === 'object' && typeof module !== 'undefined'
15 ? (module.exports = factory(require('react')))
16 : typeof define === 'function' && define.amd // eslint-disable-line no-undef
17 - ? define(['react'], factory) // eslint-disable-line no-undef
18 - : (global.SchedulerTracing = factory(global));
17 + ? define(['react'], factory) // eslint-disable-line no-undef
18 + : (global.SchedulerTracing = factory(global));
19 })(this, function(global) {
20 function unstable_clear() {
21 return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTracing.unstable_clear.apply(
packages/scheduler/npm/umd/scheduler.development.js
+2 -2
@@ -16,8 +16,8 @@
16 typeof exports === 'object' && typeof module !== 'undefined'
17 ? (module.exports = factory(require('react')))
18 : typeof define === 'function' && define.amd // eslint-disable-line no-undef
19 - ? define(['react'], factory) // eslint-disable-line no-undef
20 - : (global.Scheduler = factory(global));
19 + ? define(['react'], factory) // eslint-disable-line no-undef
20 + : (global.Scheduler = factory(global));
21 })(this, function(global) {
22 function unstable_now() {
23 return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Scheduler.unstable_now.apply(
packages/scheduler/npm/umd/scheduler.production.min.js
+2 -2
@@ -16,8 +16,8 @@
16 typeof exports === 'object' && typeof module !== 'undefined'
17 ? (module.exports = factory(require('react')))
18 : typeof define === 'function' && define.amd // eslint-disable-line no-undef
19 - ? define(['react'], factory) // eslint-disable-line no-undef
20 - : (global.Scheduler = factory(global));
19 + ? define(['react'], factory) // eslint-disable-line no-undef
20 + : (global.Scheduler = factory(global));
21 })(this, function(global) {
22 function unstable_now() {
23 return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Scheduler.unstable_now.apply(
packages/scheduler/npm/umd/scheduler.profiling.min.js
+2 -2
@@ -16,8 +16,8 @@
16 typeof exports === 'object' && typeof module !== 'undefined'
17 ? (module.exports = factory(require('react')))
18 : typeof define === 'function' && define.amd // eslint-disable-line no-undef
19 - ? define(['react'], factory) // eslint-disable-line no-undef
20 - : (global.Scheduler = factory(global));
19 + ? define(['react'], factory) // eslint-disable-line no-undef
20 + : (global.Scheduler = factory(global));
21 })(this, function(global) {
22 function unstable_now() {
23 return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Scheduler.unstable_now.apply(
packages/scheduler/src/SchedulerProfiling.js
+3 -3
@@ -21,9 +21,9 @@ export const sharedProfilingBuffer = enableProfiling
21 typeof SharedArrayBuffer === 'function'
22 ? new SharedArrayBuffer(profilingStateSize * Int32Array.BYTES_PER_ELEMENT)
23 : // $FlowFixMe Flow doesn't know about ArrayBuffer
24 - typeof ArrayBuffer === 'function'
25 - ? new ArrayBuffer(profilingStateSize * Int32Array.BYTES_PER_ELEMENT)
26 - : null // Don't crash the init path on IE9
24 + typeof ArrayBuffer === 'function'
25 + ? new ArrayBuffer(profilingStateSize * Int32Array.BYTES_PER_ELEMENT)
26 + : null // Don't crash the init path on IE9
27 : null;
28
29 const profilingState =
packages/scheduler/src/__tests__/Scheduler-test.js
+29 -5
@@ -154,7 +154,11 @@ describe('Scheduler', () => {
154 });
155
156 let didYield = false;
157 - const tasks = [['C1', 100], ['C2', 100], ['C3', 100]];
157 + const tasks = [
158 + ['C1', 100],
159 + ['C2', 100],
160 + ['C3', 100],
161 + ];
162 const C = () => {
163 while (tasks.length > 0) {
164 const [label, ms] = tasks.shift();
@@ -188,7 +192,12 @@ describe('Scheduler', () => {
192 });
193
194 it('continuation callbacks inherit the expiration of the previous callback', () => {
191 - const tasks = [['A', 125], ['B', 124], ['C', 100], ['D', 100]];
195 + const tasks = [
196 + ['A', 125],
197 + ['B', 124],
198 + ['C', 100],
199 + ['D', 100],
200 + ];
201 const work = () => {
202 while (tasks.length > 0) {
203 const [label, ms] = tasks.shift();
@@ -212,7 +221,12 @@ describe('Scheduler', () => {
221 });
222
223 it('continuations are interrupted by higher priority work', () => {
215 - const tasks = [['A', 100], ['B', 100], ['C', 100], ['D', 100]];
224 + const tasks = [
225 + ['A', 100],
226 + ['B', 100],
227 + ['C', 100],
228 + ['D', 100],
229 + ];
230 const work = () => {
231 while (tasks.length > 0) {
232 const [label, ms] = tasks.shift();
@@ -238,7 +252,12 @@ describe('Scheduler', () => {
252 'continuations are interrupted by higher priority work scheduled ' +
253 'inside an executing callback',
254 () => {
241 - const tasks = [['A', 100], ['B', 100], ['C', 100], ['D', 100]];
255 + const tasks = [
256 + ['A', 100],
257 + ['B', 100],
258 + ['C', 100],
259 + ['D', 100],
260 + ];
261 const work = () => {
262 while (tasks.length > 0) {
263 const task = tasks.shift();
@@ -631,7 +650,12 @@ describe('Scheduler', () => {
650 );
651
652 // Schedule a time-sliced task at default priority.
634 - const tasks = [['A', 100], ['B', 100], ['C', 100], ['D', 100]];
653 + const tasks = [
654 + ['A', 100],
655 + ['B', 100],
656 + ['C', 100],
657 + ['D', 100],
658 + ];
659 const work = () => {
660 while (tasks.length > 0) {
661 const task = tasks.shift();
packages/shared/objectIs.js
+1 -1
@@ -17,4 +17,4 @@ function is(x: any, y: any) {
17 );
18 }
19
20 -export default (typeof Object.is === 'function' ? Object.is : is);
20 +export default typeof Object.is === 'function' ? Object.is : is;
packages/use-subscription/src/useSubscription.js
+50 -53
@@ -67,61 +67,58 @@ export function useSubscription<Value>({
67 // This also has an added benefit when multiple components are subscribed to the same source:
68 // It allows each of the event handlers to safely schedule work without potentially removing an another handler.
69 // (Learn more at https://codesandbox.io/s/k0yvr5970o)
70 - useEffect(
71 - () => {
72 - let didUnsubscribe = false;
73 -
74 - const checkForUpdates = () => {
75 - // It's possible that this callback will be invoked even after being unsubscribed,
76 - // if it's removed as a result of a subscription event/update.
77 - // In this case, React will log a DEV warning about an update from an unmounted component.
78 - // We can avoid triggering that warning with this check.
79 - if (didUnsubscribe) {
80 - return;
70 + useEffect(() => {
71 + let didUnsubscribe = false;
72 +
73 + const checkForUpdates = () => {
74 + // It's possible that this callback will be invoked even after being unsubscribed,
75 + // if it's removed as a result of a subscription event/update.
76 + // In this case, React will log a DEV warning about an update from an unmounted component.
77 + // We can avoid triggering that warning with this check.
78 + if (didUnsubscribe) {
79 + return;
80 + }
81 +
82 + // We use a state updater function to avoid scheduling work for a stale source.
83 + // However it's important to eagerly read the currently value,
84 + // so that all scheduled work shares the same value (in the event of multiple subscriptions).
85 + // This avoids visual "tearing" when a mutation happens during a (concurrent) render.
86 + const value = getCurrentValue();
87 +
88 + setState(prevState => {
89 + // Ignore values from stale sources!
90 + // Since we subscribe an unsubscribe in a passive effect,
91 + // it's possible that this callback will be invoked for a stale (previous) subscription.
92 + // This check avoids scheduling an update for that stale subscription.
93 + if (
94 + prevState.getCurrentValue !== getCurrentValue ||
95 + prevState.subscribe !== subscribe
96 + ) {
97 + return prevState;
98 }
99
83 - // We use a state updater function to avoid scheduling work for a stale source.
84 - // However it's important to eagerly read the currently value,
85 - // so that all scheduled work shares the same value (in the event of multiple subscriptions).
86 - // This avoids visual "tearing" when a mutation happens during a (concurrent) render.
87 - const value = getCurrentValue();
88 -
89 - setState(prevState => {
90 - // Ignore values from stale sources!
91 - // Since we subscribe an unsubscribe in a passive effect,
92 - // it's possible that this callback will be invoked for a stale (previous) subscription.
93 - // This check avoids scheduling an update for that stale subscription.
94 - if (
95 - prevState.getCurrentValue !== getCurrentValue ||
96 - prevState.subscribe !== subscribe
97 - ) {
98 - return prevState;
99 - }
100 -
101 - // Some subscriptions will auto-invoke the handler, even if the value hasn't changed.
102 - // If the value hasn't changed, no update is needed.
103 - // Return state as-is so React can bail out and avoid an unnecessary render.
104 - if (prevState.value === value) {
105 - return prevState;
106 - }
107 -
108 - return {...prevState, value};
109 - });
110 - };
111 - const unsubscribe = subscribe(checkForUpdates);
112 -
113 - // Because we're subscribing in a passive effect,
114 - // it's possible that an update has occurred between render and our effect handler.
115 - // Check for this and schedule an update if work has occurred.
116 - checkForUpdates();
117 -
118 - return () => {
119 - didUnsubscribe = true;
120 - unsubscribe();
121 - };
122 - },
123 - [getCurrentValue, subscribe],
124 - );
100 + // Some subscriptions will auto-invoke the handler, even if the value hasn't changed.
101 + // If the value hasn't changed, no update is needed.
102 + // Return state as-is so React can bail out and avoid an unnecessary render.
103 + if (prevState.value === value) {
104 + return prevState;
105 + }
106 +
107 + return {...prevState, value};
108 + });
109 + };
110 + const unsubscribe = subscribe(checkForUpdates);
111 +
112 + // Because we're subscribing in a passive effect,
113 + // it's possible that an update has occurred between render and our effect handler.
114 + // Check for this and schedule an update if work has occurred.
115 + checkForUpdates();
116 +
117 + return () => {
118 + didUnsubscribe = true;
119 + unsubscribe();
120 + };
121 + }, [getCurrentValue, subscribe]);
122
123 // Return the current value for our caller to use while rendering.
124 return valueToReturn;
scripts/jest/matchers/interactionTracingMatchers.js
+1 -3
@@ -77,9 +77,7 @@ function toMatchInteractions(actualSetOrArray, expectedSetOrArray) {
77 if (actualArray.length !== expectedArray.length) {
78 return {
79 message: () =>
80 - `Expected ${expectedArray.length} interactions but there were ${
81 - actualArray.length
82 - }`,
80 + `Expected ${expectedArray.length} interactions but there were ${actualArray.length}`,
81 pass: false,
82 };
83 }
scripts/jest/matchers/profilerMatchers.js
+1 -3
@@ -51,9 +51,7 @@ function toMatchInteractions(actualSetOrArray, expectedSetOrArray) {
51 if (actualArray.length !== expectedArray.length) {
52 return {
53 message: () =>
54 - `Expected ${expectedArray.length} interactions but there were ${
55 - actualArray.length
56 - }`,
54 + `Expected ${expectedArray.length} interactions but there were ${actualArray.length}`,
55 pass: false,
56 };
57 }
scripts/jest/matchers/toWarnDev.js
+1 -3
@@ -177,9 +177,7 @@ const createMatcherFor = (consoleMethod, matcherName) =>
177 if (withoutStack !== warningsWithoutComponentStack.length) {
178 return {
179 message: () =>
180 - `Expected ${withoutStack} warnings without a component stack but received ${
181 - warningsWithoutComponentStack.length
182 - }:\n` +
180 + `Expected ${withoutStack} warnings without a component stack but received ${warningsWithoutComponentStack.length}:\n` +
181 warningsWithoutComponentStack.map(warning =>
182 this.utils.printReceived(warning)
183 ),
scripts/jest/setupHostConfigs.js
+6 -18
@@ -57,9 +57,7 @@ inlinedHostConfigs.forEach(rendererInfo => {
57 jest.mock(shimHostConfigPath, () => {
58 hasImportedShimmedConfig = true;
59 return require.requireActual(
60 - `react-reconciler/src/forks/ReactFiberHostConfig.${
61 - rendererInfo.shortName
62 - }.js`
60 + `react-reconciler/src/forks/ReactFiberHostConfig.${rendererInfo.shortName}.js`
61 );
62 });
63
@@ -88,17 +86,13 @@ inlinedHostConfigs.forEach(rendererInfo => {
86 jest.mock(shimServerHostConfigPath, () => {
87 hasImportedShimmedConfig = true;
88 return require.requireActual(
91 - `react-server/src/forks/ReactServerHostConfig.${
92 - rendererInfo.shortName
93 - }.js`
89 + `react-server/src/forks/ReactServerHostConfig.${rendererInfo.shortName}.js`
90 );
91 });
92 jest.mock(shimServerFormatConfigPath, () => {
93 hasImportedShimmedConfig = true;
94 return require.requireActual(
99 - `react-server/src/forks/ReactServerFormatConfig.${
100 - rendererInfo.shortName
101 - }.js`
95 + `react-server/src/forks/ReactServerFormatConfig.${rendererInfo.shortName}.js`
96 );
97 });
98
@@ -126,17 +120,13 @@ inlinedHostConfigs.forEach(rendererInfo => {
120 jest.mock(shimServerHostConfigPath, () => {
121 hasImportedShimmedConfig = true;
122 return require.requireActual(
129 - `react-server/src/forks/ReactServerHostConfig.${
130 - rendererInfo.shortName
131 - }.js`
123 + `react-server/src/forks/ReactServerHostConfig.${rendererInfo.shortName}.js`
124 );
125 });
126 jest.mock(shimServerFormatConfigPath, () => {
127 hasImportedShimmedConfig = true;
128 return require.requireActual(
137 - `react-server/src/forks/ReactServerFormatConfig.${
138 - rendererInfo.shortName
139 - }.js`
129 + `react-server/src/forks/ReactServerFormatConfig.${rendererInfo.shortName}.js`
130 );
131 });
132
@@ -164,9 +154,7 @@ inlinedHostConfigs.forEach(rendererInfo => {
154 jest.mock(shimFlightClientHostConfigPath, () => {
155 hasImportedShimmedConfig = true;
156 return require.requireActual(
167 - `react-flight/src/forks/ReactFlightClientHostConfig.${
168 - rendererInfo.shortName
169 - }.js`
157 + `react-flight/src/forks/ReactFlightClientHostConfig.${rendererInfo.shortName}.js`
158 );
159 });
160
scripts/release/create-canary-commands/copy-repo-to-temp-directory.js
+1 -3
@@ -27,8 +27,6 @@ const run = async ({commit, cwd, tempDirectory}) => {
27 module.exports = async params => {
28 return logPromise(
29 run(params),
30 - theme`Copying React repo to temporary directory ({path ${
31 - params.tempDirectory
32 - }})`
30 + theme`Copying React repo to temporary directory ({path ${params.tempDirectory}})`
31 );
32 };
scripts/release/create-canary-commands/npm-pack-and-unpack.js
+2 -6
@@ -32,18 +32,14 @@ const run = async ({cwd, dry, tempDirectory}) => {
32 const compressedPackages = readdirSync(join(cwd, 'build/node_modules/'));
33 for (let i = 0; i < compressedPackages.length; i++) {
34 await exec(
35 - `tar -zxvf ./build/node_modules/${
36 - compressedPackages[i]
37 - } -C ./build/node_modules/`,
35 + `tar -zxvf ./build/node_modules/${compressedPackages[i]} -C ./build/node_modules/`,
36 {cwd}
37 );
38 const packageJSON = readJsonSync(
39 join(cwd, `./build/node_modules/package/package.json`)
40 );
41 await exec(
44 - `mv ./build/node_modules/package ./build/node_modules/${
45 - packageJSON.name
46 - }`,
42 + `mv ./build/node_modules/package ./build/node_modules/${packageJSON.name}`,
43 {cwd}
44 );
45 }
scripts/release/prepare-stable-commands/update-stable-version-numbers.js
+1 -3
@@ -90,9 +90,7 @@ const run = async ({cwd, packages, version}, versionsMap) => {
90 for (let dependencyName in maybeDependency) {
91 if (packages.includes(dependencyName)) {
92 console.log(
93 - theme`• {package ${dependencyName}} {version ${
94 - maybeDependency[dependencyName]
95 - }} {dimmed ${label}}`
93 + theme`• {package ${dependencyName}} {version ${maybeDependency[dependencyName]}} {dimmed ${label}}`
94 );
95 }
96 }
scripts/release/publish-commands/publish-to-npm.js
+2 -6
@@ -44,17 +44,13 @@ const run = async ({cwd, dry, packages, tags}, otp) => {
44 for (let j = 1; j < tags.length; j++) {
45 if (!dry) {
46 await exec(
47 - `npm dist-tag add ${packageName}@${version} ${
48 - tags[j]
49 - } --otp=${otp}`,
47 + `npm dist-tag add ${packageName}@${version} ${tags[j]} --otp=${otp}`,
48 {cwd: packagePath}
49 );
50 }
51 console.log(
52 theme.command(
55 - ` npm dist-tag add ${packageName}@${version} ${
56 - tags[j]
57 - } --otp=${otp}`
53 + ` npm dist-tag add ${packageName}@${version} ${tags[j]} --otp=${otp}`
54 )
55 );
56 }
scripts/release/shared-commands/download-build-artifacts.js
+2 -6
@@ -40,18 +40,14 @@ const run = async ({build, cwd}) => {
40 const compressedPackages = readdirSync(join(cwd, 'build/node_modules/'));
41 for (let i = 0; i < compressedPackages.length; i++) {
42 await exec(
43 - `tar zxvf ./build/node_modules/${
44 - compressedPackages[i]
45 - } -C ./build/node_modules/`,
43 + `tar zxvf ./build/node_modules/${compressedPackages[i]} -C ./build/node_modules/`,
44 {cwd}
45 );
46 const packageJSON = readJsonSync(
47 join(cwd, `/build/node_modules/package/package.json`)
48 );
49 await exec(
52 - `mv ./build/node_modules/package ./build/node_modules/${
53 - packageJSON.name
54 - }`,
50 + `mv ./build/node_modules/package ./build/node_modules/${packageJSON.name}`,
51 {cwd}
52 );
53 }
scripts/release/utils.js
+3 -9
@@ -41,9 +41,7 @@ const execRead = async (command, options) => {
41 };
42
43 const getArtifactsList = async buildID => {
44 - const buildMetadataURL = `https://circleci.com/api/v1.1/project/github/facebook/react/${buildID}?circle-token=${
45 - process.env.CIRCLE_CI_API_TOKEN
46 - }`;
44 + const buildMetadataURL = `https://circleci.com/api/v1.1/project/github/facebook/react/${buildID}?circle-token=${process.env.CIRCLE_CI_API_TOKEN}`;
45 const buildMetadata = await http.get(buildMetadataURL, true);
46 if (!buildMetadata.workflows || !buildMetadata.workflows.workflow_id) {
47 console.log(
@@ -57,9 +55,7 @@ const getArtifactsList = async buildID => {
55 ? 'process_artifacts_experimental'
56 : 'process_artifacts';
57 const workflowID = buildMetadata.workflows.workflow_id;
60 - const workflowMetadataURL = `https://circleci.com/api/v2/workflow/${workflowID}/job?circle-token=${
61 - process.env.CIRCLE_CI_API_TOKEN
62 - }`;
58 + const workflowMetadataURL = `https://circleci.com/api/v2/workflow/${workflowID}/job?circle-token=${process.env.CIRCLE_CI_API_TOKEN}`;
59 const workflowMetadata = await http.get(workflowMetadataURL, true);
60 const job = workflowMetadata.items.find(
61 ({name}) => name === artifactsJobName
@@ -71,9 +67,7 @@ const getArtifactsList = async buildID => {
67 process.exit(1);
68 }
69
74 - const jobArtifactsURL = `https://circleci.com/api/v1.1/project/github/facebook/react/${
75 - job.job_number
76 - }/artifacts?circle-token=${process.env.CIRCLE_CI_API_TOKEN}`;
70 + const jobArtifactsURL = `https://circleci.com/api/v1.1/project/github/facebook/react/${job.job_number}/artifacts?circle-token=${process.env.CIRCLE_CI_API_TOKEN}`;
71 const jobArtifacts = await http.get(jobArtifactsURL, true);
72
73 return jobArtifacts;
scripts/rollup/forks.js
+4 -12
@@ -278,9 +278,7 @@ const forks = Object.freeze({
278 // eslint-disable-next-line no-for-of-loops/no-for-of-loops
279 for (let rendererInfo of inlinedHostConfigs) {
280 if (rendererInfo.entryPoints.indexOf(entry) !== -1) {
281 - return `react-reconciler/src/forks/ReactFiberHostConfig.${
282 - rendererInfo.shortName
283 - }.js`;
281 + return `react-reconciler/src/forks/ReactFiberHostConfig.${rendererInfo.shortName}.js`;
282 }
283 }
284 throw new Error(
@@ -308,9 +306,7 @@ const forks = Object.freeze({
306 if (!rendererInfo.isServerSupported) {
307 return null;
308 }
311 - return `react-server/src/forks/ReactServerHostConfig.${
312 - rendererInfo.shortName
313 - }.js`;
309 + return `react-server/src/forks/ReactServerHostConfig.${rendererInfo.shortName}.js`;
310 }
311 }
312 throw new Error(
@@ -338,9 +334,7 @@ const forks = Object.freeze({
334 if (!rendererInfo.isServerSupported) {
335 return null;
336 }
341 - return `react-server/src/forks/ReactServerFormatConfig.${
342 - rendererInfo.shortName
343 - }.js`;
337 + return `react-server/src/forks/ReactServerFormatConfig.${rendererInfo.shortName}.js`;
338 }
339 }
340 throw new Error(
@@ -368,9 +362,7 @@ const forks = Object.freeze({
362 if (!rendererInfo.isServerSupported) {
363 return null;
364 }
371 - return `react-flight/src/forks/ReactFlightClientHostConfig.${
372 - rendererInfo.shortName
373 - }.js`;
365 + return `react-flight/src/forks/ReactFlightClientHostConfig.${rendererInfo.shortName}.js`;
366 }
367 }
368 throw new Error(
scripts/rollup/packaging.js
+3 -3
@@ -135,9 +135,9 @@ async function prepareNpmPackage(name) {
135 ),
136 asyncCopyTo(`packages/${name}/npm`, `build/node_modules/${name}`),
137 ]);
138 - const tgzName = (await asyncExecuteCommand(
139 - `npm pack build/node_modules/${name}`
140 - )).trim();
138 + const tgzName = (
139 + await asyncExecuteCommand(`npm pack build/node_modules/${name}`)
140 + ).trim();
141 await asyncRimRaf(`build/node_modules/${name}`);
142 await asyncExtractTar(getTarOptions(tgzName, name));
143 unlinkSync(tgzName);
scripts/rollup/wrappers.js
+24 -24
@@ -71,14 +71,14 @@ ${license}
71 'use strict';
72
73 ${
74 - globalName === 'ReactNoopRenderer' ||
75 - globalName === 'ReactNoopRendererPersistent'
76 - ? // React Noop needs regenerator runtime because it uses
77 - // generators but GCC doesn't handle them in the output.
78 - // So we use Babel for them.
79 - `const regeneratorRuntime = require("regenerator-runtime");`
80 - : ``
81 - }
74 + globalName === 'ReactNoopRenderer' ||
75 + globalName === 'ReactNoopRendererPersistent'
76 + ? // React Noop needs regenerator runtime because it uses
77 + // generators but GCC doesn't handle them in the output.
78 + // So we use Babel for them.
79 + `const regeneratorRuntime = require("regenerator-runtime");`
80 + : ``
81 +}
82
83 if (process.env.NODE_ENV !== "production") {
84 (function() {
@@ -95,14 +95,14 @@ ${source}
95 ${license}
96 */
97 ${
98 - globalName === 'ReactNoopRenderer' ||
99 - globalName === 'ReactNoopRendererPersistent'
100 - ? // React Noop needs regenerator runtime because it uses
101 - // generators but GCC doesn't handle them in the output.
102 - // So we use Babel for them.
103 - `const regeneratorRuntime = require("regenerator-runtime");`
104 - : ``
105 - }
98 + globalName === 'ReactNoopRenderer' ||
99 + globalName === 'ReactNoopRendererPersistent'
100 + ? // React Noop needs regenerator runtime because it uses
101 + // generators but GCC doesn't handle them in the output.
102 + // So we use Babel for them.
103 + `const regeneratorRuntime = require("regenerator-runtime");`
104 + : ``
105 +}
106 ${source}`;
107 },
108
@@ -114,14 +114,14 @@ ${source}`;
114 ${license}
115 */
116 ${
117 - globalName === 'ReactNoopRenderer' ||
118 - globalName === 'ReactNoopRendererPersistent'
119 - ? // React Noop needs regenerator runtime because it uses
120 - // generators but GCC doesn't handle them in the output.
121 - // So we use Babel for them.
122 - `const regeneratorRuntime = require("regenerator-runtime");`
123 - : ``
124 - }
117 + globalName === 'ReactNoopRenderer' ||
118 + globalName === 'ReactNoopRendererPersistent'
119 + ? // React Noop needs regenerator runtime because it uses
120 + // generators but GCC doesn't handle them in the output.
121 + // So we use Babel for them.
122 + `const regeneratorRuntime = require("regenerator-runtime");`
123 + : ``
124 +}
125 ${source}`;
126 },
127
yarn.lock
+7 -1
@@ -4864,6 +4864,7 @@ eslint-plugin-no-unsafe-innerhtml@1.0.16:
4864
4865 "eslint-plugin-react-internal@link:./scripts/eslint-rules":
4866 version "0.0.0"
4867 + uid ""
4868
4869 eslint-plugin-react@^6.7.1:
4870 version "6.10.3"
@@ -10059,7 +10060,12 @@ preserve@^0.2.0:
10060 resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
10061 integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=
10062
10062 -prettier@1.13.7, prettier@^1.0.0:
10063 +prettier@1.19.1:
10064 + version "1.19.1"
10065 + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
10066 + integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==
10067 +
10068 +prettier@^1.0.0:
10069 version "1.13.7"
10070 resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.13.7.tgz#850f3b8af784a49a6ea2d2eaa7ed1428a34b7281"
10071 integrity sha512-KIU72UmYPGk4MujZGYMFwinB7lOf2LsDNGSOC8ufevsrPLISrZbNJlWstRi3m0AMuszbH+EFSQ/r6w56RSPK6w==