@samitouri / QOS-React / commits / a89854bc93

Fix Suspense-wrapping heuristic (and bump version numbers) (#19373)

* Fixed suspense wrapping heuristic * Bump package numbers 16.13.1 -> 17.0.0-alpha.0 to fix DevTools Suspense heuristic

Brian Vaughn committed Jul 15, 2020 at 12:25 UTC a89854bc936668d325cac9a22e2ebfa128c7addf
22 files changed +165 -33
packages/create-subscription/package.json
+2 -2
@@ -1,7 +1,7 @@
1 {
2 "name": "create-subscription",
3 "description": "utility for subscribing to external data sources inside React components",
4 - "version": "16.13.1",
4 + "version": "17.0.0-alpha.0",
5 "repository": {
6 "type": "git",
7 "url": "https://github.com/facebook/react.git",
@@ -15,7 +15,7 @@
15 "cjs/"
16 ],
17 "peerDependencies": {
18 - "react": "^16.3.0"
18 + "react": "^17.0.0-alpha"
19 },
20 "devDependencies": {
21 "rxjs": "^5.5.6"
packages/jest-react/package.json
+3 -3
@@ -1,6 +1,6 @@
1 {
2 "name": "jest-react",
3 - "version": "0.11.1",
3 + "version": "0.12.0-alpha.0",
4 "description": "Jest matchers and utilities for testing React components.",
5 "main": "index.js",
6 "repository": {
@@ -20,8 +20,8 @@
20 "homepage": "https://reactjs.org/",
21 "peerDependencies": {
22 "jest": "^23.0.1 || ^24.0.0 || ^25.1.0",
23 - "react": "^16.0.0",
24 - "react-test-renderer": "^16.0.0"
23 + "react": "^17.0.0-alpha",
24 + "react-test-renderer": "^17.0.0-alpha"
25 },
26 "dependencies": {
27 "object-assign": "^4.1.1"
packages/react-art/package.json
+2 -2
@@ -1,7 +1,7 @@
1 {
2 "name": "react-art",
3 "description": "React ART is a JavaScript library for drawing vector graphics using React. It provides declarative and reactive bindings to the ART library. Using the same declarative API you can render the output to either Canvas, SVG or VML (IE8).",
4 - "version": "16.13.1",
4 + "version": "17.0.0-alpha.0",
5 "main": "index.js",
6 "repository": {
7 "type": "git",
@@ -29,7 +29,7 @@
29 "scheduler": "^0.19.0"
30 },
31 "peerDependencies": {
32 - "react": "^16.13.0"
32 + "react": "^17.0.0-alpha"
33 },
34 "files": [
35 "LICENSE",
packages/react-cache/package.json
+1 -1
@@ -17,6 +17,6 @@
17 "umd/"
18 ],
19 "peerDependencies": {
20 - "react": "^16.3.0-alpha.1"
20 + "react": "^17.0.0-alpha"
21 }
22 }
packages/react-client/package.json
+1 -1
@@ -24,7 +24,7 @@
24 "node": ">=0.10.0"
25 },
26 "peerDependencies": {
27 - "react": "^16.0.0"
27 + "react": "^17.0.0-alpha"
28 },
29 "dependencies": {
30 "loose-envify": "^1.1.0",
packages/react-debug-tools/package.json
+1 -1
@@ -26,7 +26,7 @@
26 "node": ">=0.10.0"
27 },
28 "peerDependencies": {
29 - "react": "^16.0.0"
29 + "react": "^17.0.0-alpha"
30 },
31 "dependencies": {
32 "error-stack-parser": "^2.0.2",
packages/react-devtools-shared/src/__tests__/profilingCache-test.js
+89
@@ -716,4 +716,93 @@ describe('ProfilingCache', () => {
716 TestRenderer.create(<Validator commitIndex={0} rootID={rootID} />);
717 });
718 });
719 +
720 + // See https://github.com/facebook/react/issues/18831
721 + it('should not crash during route transitions with Suspense', () => {
722 + const RouterContext = React.createContext();
723 +
724 + function App() {
725 + return (
726 + <Router>
727 + <Switch>
728 + <Route path="/">
729 + <Home />
730 + </Route>
731 + <Route path="/about">
732 + <About />
733 + </Route>
734 + </Switch>
735 + </Router>
736 + );
737 + }
738 +
739 + const Home = () => {
740 + return (
741 + <React.Suspense>
742 + <Link path="/about">Home</Link>
743 + </React.Suspense>
744 + );
745 + };
746 +
747 + const About = () => <div>About</div>;
748 +
749 + // Mimics https://github.com/ReactTraining/react-router/blob/master/packages/react-router/modules/Router.js
750 + function Router({children}) {
751 + const [path, setPath] = React.useState('/');
752 + return (
753 + <RouterContext.Provider value={{path, setPath}}>
754 + {children}
755 + </RouterContext.Provider>
756 + );
757 + }
758 +
759 + // Mimics https://github.com/ReactTraining/react-router/blob/master/packages/react-router/modules/Switch.js
760 + function Switch({children}) {
761 + return (
762 + <RouterContext.Consumer>
763 + {context => {
764 + let element = null;
765 + React.Children.forEach(children, child => {
766 + if (context.path === child.props.path) {
767 + element = child.props.children;
768 + }
769 + });
770 + return element ? React.cloneElement(element) : null;
771 + }}
772 + </RouterContext.Consumer>
773 + );
774 + }
775 +
776 + // Mimics https://github.com/ReactTraining/react-router/blob/master/packages/react-router/modules/Route.js
777 + function Route({children, path}) {
778 + return null;
779 + }
780 +
781 + const linkRef = React.createRef();
782 +
783 + // Mimics https://github.com/ReactTraining/react-router/blob/master/packages/react-router-dom/modules/Link.js
784 + function Link({children, path}) {
785 + return (
786 + <RouterContext.Consumer>
787 + {context => {
788 + return (
789 + <button ref={linkRef} onClick={() => context.setPath(path)}>
790 + {children}
791 + </button>
792 + );
793 + }}
794 + </RouterContext.Consumer>
795 + );
796 + }
797 +
798 + const {Simulate} = require('react-dom/test-utils');
799 +
800 + const container = document.createElement('div');
801 + utils.act(() => ReactDOM.render(<App />, container));
802 + expect(container.textContent).toBe('Home');
803 + utils.act(() => store.profilerStore.startProfiling());
804 + utils.act(() => Simulate.click(linkRef.current));
805 + utils.act(() => store.profilerStore.stopProfiling());
806 + expect(container.textContent).toBe('About');
807 + });
808 });
packages/react-devtools-shared/src/backend/renderer.js
+44 -4
@@ -153,7 +153,8 @@ export function getInternalReactConstants(
153 // **********************************************************
154 // The section below is copied from files in React repo.
155 // Keep it in sync, and add version guards if it changes.
156 - if (gte(version, '16.6.0-beta.0')) {
156 + if (gte(version, '17.0.0-alpha')) {
157 + // TODO (Offscreen) Update the version number above to reflect the first Offscreen alpha/beta release.
158 ReactTypeOfWork = {
159 Block: 22,
160 ClassComponent: 1,
@@ -181,6 +182,34 @@ export function getInternalReactConstants(
182 SuspenseListComponent: 19, // Experimental
183 YieldComponent: -1, // Removed
184 };
185 + } else if (gte(version, '16.6.0-beta.0')) {
186 + ReactTypeOfWork = {
187 + Block: 22,
188 + ClassComponent: 1,
189 + ContextConsumer: 9,
190 + ContextProvider: 10,
191 + CoroutineComponent: -1, // Removed
192 + CoroutineHandlerPhase: -1, // Removed
193 + DehydratedSuspenseComponent: 18, // Behind a flag
194 + ForwardRef: 11,
195 + Fragment: 7,
196 + FunctionComponent: 0,
197 + HostComponent: 5,
198 + HostPortal: 4,
199 + HostRoot: 3,
200 + HostText: 6,
201 + IncompleteClassComponent: 17,
202 + IndeterminateComponent: 2,
203 + LazyComponent: 16,
204 + MemoComponent: 14,
205 + Mode: 8,
206 + OffscreenComponent: -1, // Experimental
207 + Profiler: 12,
208 + SimpleMemoComponent: 15,
209 + SuspenseComponent: 13,
210 + SuspenseListComponent: 19, // Experimental
211 + YieldComponent: -1, // Removed
212 + };
213 } else if (gte(version, '16.4.3-alpha')) {
214 ReactTypeOfWork = {
215 Block: -1, // Doesn't exist yet
@@ -452,14 +481,16 @@ export function attach(
481 const debug = (name: string, fiber: Fiber, parentFiber: ?Fiber): void => {
482 if (__DEBUG__) {
483 const displayName = getDisplayNameForFiber(fiber) || 'null';
484 + const id = getFiberID(fiber);
485 const parentDisplayName =
486 (parentFiber != null && getDisplayNameForFiber(parentFiber)) || 'null';
487 + const parentID = parentFiber ? getFiberID(parentFiber) : '';
488 // NOTE: calling getFiberID or getPrimaryFiber is unsafe here
489 // because it will put them in the map. For now, we'll omit them.
490 // TODO: better debugging story for this.
491 console.log(
461 - `[renderer] %c${name} %c${displayName} %c${
462 - parentFiber ? parentDisplayName : ''
492 + `[renderer] %c${name} %c${displayName} (${id}) %c${
493 + parentFiber ? `${parentDisplayName} (${parentID})` : ''
494 }`,
495 'color: red; font-weight: bold;',
496 'color: blue;',
@@ -1076,6 +1107,10 @@ export function attach(
1107 }
1108
1109 function recordMount(fiber: Fiber, parentFiber: Fiber | null) {
1110 + if (__DEBUG__) {
1111 + debug('recordMount()', fiber, parentFiber);
1112 + }
1113 +
1114 const isRoot = fiber.tag === HostRoot;
1115 const id = getFiberID(getPrimaryFiber(fiber));
1116
@@ -1130,6 +1165,10 @@ export function attach(
1165 }
1166
1167 function recordUnmount(fiber: Fiber, isSimulated: boolean) {
1168 + if (__DEBUG__) {
1169 + debug('recordUnmount()', fiber);
1170 + }
1171 +
1172 if (trackedPathMatchFiber !== null) {
1173 // We're in the process of trying to restore previous selection.
1174 // If this fiber matched but is being unmounted, there's no use trying.
@@ -1215,7 +1254,8 @@ export function attach(
1254 // because we don't want to highlight every host node inside of a newly mounted subtree.
1255 }
1256
1218 - if (fiber.tag === ReactTypeOfWork.SuspenseComponent) {
1257 + const isSuspense = fiber.tag === ReactTypeOfWork.SuspenseComponent;
1258 + if (isSuspense) {
1259 const isTimedOut = fiber.memoizedState !== null;
1260 if (isTimedOut) {
1261 // Special case: if Suspense mounts in a timed-out state,
packages/react-dom/package.json
+2 -2
@@ -1,6 +1,6 @@
1 {
2 "name": "react-dom",
3 - "version": "16.13.1",
3 + "version": "17.0.0-alpha.0",
4 "description": "React package for working with the DOM.",
5 "main": "index.js",
6 "repository": {
@@ -22,7 +22,7 @@
22 "scheduler": "^0.19.0"
23 },
24 "peerDependencies": {
25 - "react": "^16.13.0"
25 + "react": "^17.0.0-alpha"
26 },
27 "files": [
28 "LICENSE",
packages/react-fetch/package.json
+1 -1
@@ -18,7 +18,7 @@
18 "cjs/"
19 ],
20 "peerDependencies": {
21 - "react": "^16.13.1"
21 + "react": "^17.0.0-alpha"
22 },
23 "browser": {
24 "./index.js": "./index.browser.js"
packages/react-interactions/package.json
+1 -1
@@ -38,7 +38,7 @@
38 "loose-envify": "^1.1.0"
39 },
40 "peerDependencies": {
41 - "react": "^16.0.0"
41 + "react": "^17.0.0-alpha"
42 },
43 "browserify": {
44 "transform": [
packages/react-is/package.json
+1 -1
@@ -1,6 +1,6 @@
1 {
2 "name": "react-is",
3 - "version": "16.13.1",
3 + "version": "17.0.0-alpha.0",
4 "description": "Brand checking of React Elements.",
5 "main": "index.js",
6 "repository": {
packages/react-native-renderer/package.json
+1 -1
@@ -12,6 +12,6 @@
12 "scheduler": "^0.11.0"
13 },
14 "peerDependencies": {
15 - "react": "^16.0.0"
15 + "react": "^17.0.0-alpha"
16 }
17 }
packages/react-noop-renderer/package.json
+1 -1
@@ -17,7 +17,7 @@
17 "react-server": "*"
18 },
19 "peerDependencies": {
20 - "react": "^16.13.0"
20 + "react": "^17.0.0-alpha"
21 },
22 "files": [
23 "LICENSE",
packages/react-reconciler/package.json
+1 -1
@@ -26,7 +26,7 @@
26 "node": ">=0.10.0"
27 },
28 "peerDependencies": {
29 - "react": "^16.13.0"
29 + "react": "^17.0.0-alpha"
30 },
31 "dependencies": {
32 "loose-envify": "^1.1.0",
packages/react-server/package.json
+1 -1
@@ -27,7 +27,7 @@
27 "node": ">=0.10.0"
28 },
29 "peerDependencies": {
30 - "react": "^16.0.0"
30 + "react": "^17.0.0-alpha"
31 },
32 "dependencies": {
33 "loose-envify": "^1.1.0",
packages/react-test-renderer/package.json
+6 -3
@@ -1,6 +1,6 @@
1 {
2 "name": "react-test-renderer",
3 - "version": "16.13.1",
3 + "version": "17.0.0-alpha.0",
4 "description": "React package for snapshot testing.",
5 "main": "index.js",
6 "repository": {
@@ -20,12 +20,15 @@
20 "homepage": "https://reactjs.org/",
21 "dependencies": {
22 "object-assign": "^4.1.1",
23 - "react-is": "^16.8.6",
23 + "react-is": "^17.0.0-alpha",
24 "react-shallow-renderer": "^16.13.1",
25 "scheduler": "^0.19.0"
26 },
27 "peerDependencies": {
28 - "react": "^16.13.0"
28 + "react": "^17.0.0-alpha"
29 + },
30 + "resolutions": {
31 + "react-shallow-renderer/react-is": "^17.0.0-alpha"
32 },
33 "files": [
34 "LICENSE",
packages/react-transport-dom-relay/package.json
+2 -2
@@ -12,7 +12,7 @@
12 "scheduler": "^0.11.0"
13 },
14 "peerDependencies": {
15 - "react": "^16.0.0",
16 - "react-dom": "^16.0.0"
15 + "react": "^17.0.0-alpha",
16 + "react-dom": "^17.0.0-alpha"
17 }
18 }
packages/react-transport-dom-webpack/package.json
+2 -2
@@ -34,8 +34,8 @@
34 "node": ">=0.10.0"
35 },
36 "peerDependencies": {
37 - "react": "^16.0.0",
38 - "react-dom": "^16.0.0",
37 + "react": "^17.0.0-alpha",
38 + "react-dom": "^17.0.0-alpha",
39 "webpack": "^4.43.0"
40 },
41 "dependencies": {
packages/react/package.json
+1 -1
@@ -4,7 +4,7 @@
4 "keywords": [
5 "react"
6 ],
7 - "version": "16.13.1",
7 + "version": "17.0.0-alpha.0",
8 "homepage": "https://reactjs.org/",
9 "bugs": "https://github.com/facebook/react/issues",
10 "license": "MIT",
packages/shared/ReactVersion.js
+1 -1
@@ -6,4 +6,4 @@
6 */
7
8 // TODO: this is special because it gets imported during build.
9 -export default '16.13.1';
9 +export default '17.0.0-alpha.0';
packages/use-subscription/package.json
+1 -1
@@ -19,7 +19,7 @@
19 "object-assign": "^4.1.1"
20 },
21 "peerDependencies": {
22 - "react": "^16.8.0"
22 + "react": "^17.0.0-alpha"
23 },
24 "devDependencies": {
25 "rxjs": "^5.5.6"