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

Add back root override for strict mode (#21428)

* Add back root override for strict mode * Switch flag to boolean * Fix flow

Ricky committed May 4, 2021 at 15:42 UTC e9a4a44aae675e1b164cf2ae509e438c324d424a
13 files changed +74 -5
packages/react-dom/src/__tests__/ReactTestUtilsAct-test.js
+14
@@ -102,6 +102,20 @@ describe('ReactTestUtils.act()', () => {
102 root.render(<App />);
103 Scheduler.unstable_flushAll();
104 });
105 +
106 + // @gate experimental
107 + it('warns in concurrent mode if root is strict', () => {
108 + expect(() => {
109 + const root = ReactDOM.unstable_createRoot(
110 + document.createElement('div'),
111 + {unstable_strictMode: true},
112 + );
113 + root.render(<App />);
114 + Scheduler.unstable_flushAll();
115 + }).toErrorDev([
116 + 'An update to App ran an effect, but was not wrapped in act(...)',
117 + ]);
118 + });
119 });
120 });
121
packages/react-dom/src/client/ReactDOMRoot.js
+3
@@ -27,6 +27,7 @@ export type RootOptions = {
27 mutableSources?: Array<MutableSource<any>>,
28 ...
29 },
30 + unstable_strictMode?: boolean,
31 unstable_concurrentUpdatesByDefault?: boolean,
32 ...
33 };
@@ -122,6 +123,7 @@ function createRootImpl(
123 options.hydrationOptions != null &&
124 options.hydrationOptions.mutableSources) ||
125 null;
126 + const isStrictMode = options != null && options.unstable_strictMode === true;
127
128 let concurrentUpdatesByDefaultOverride = null;
129 if (allowConcurrentByDefault) {
@@ -136,6 +138,7 @@ function createRootImpl(
138 tag,
139 hydrate,
140 hydrationCallbacks,
141 + isStrictMode,
142 concurrentUpdatesByDefaultOverride,
143 );
144 markContainerAsRoot(root.current, container);
packages/react-native-renderer/src/ReactFabric.js
+1 -1
@@ -207,7 +207,7 @@ function render(
207 if (!root) {
208 // TODO (bvaughn): If we decide to keep the wrapper component,
209 // We could create a wrapper for containerTag as well to reduce special casing.
210 - root = createContainer(containerTag, LegacyRoot, false, null, null);
210 + root = createContainer(containerTag, LegacyRoot, false, null, false, null);
211 roots.set(containerTag, root);
212 }
213 updateContainer(element, root, null, callback);
packages/react-native-renderer/src/ReactNativeRenderer.js
+1 -1
@@ -203,7 +203,7 @@ function render(
203 if (!root) {
204 // TODO (bvaughn): If we decide to keep the wrapper component,
205 // We could create a wrapper for containerTag as well to reduce special casing.
206 - root = createContainer(containerTag, LegacyRoot, false, null, null);
206 + root = createContainer(containerTag, LegacyRoot, false, null, false, null);
207 roots.set(containerTag, root);
208 }
209 updateContainer(element, root, null, callback);
packages/react-noop-renderer/src/createReactNoop.js
+3 -1
@@ -722,7 +722,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
722 if (!root) {
723 const container = {rootID: rootID, pendingChildren: [], children: []};
724 rootContainers.set(rootID, container);
725 - root = NoopRenderer.createContainer(container, tag, false, null);
725 + root = NoopRenderer.createContainer(container, tag, false, null, null);
726 roots.set(rootID, root);
727 }
728 return root.current.stateNode.containerInfo;
@@ -740,6 +740,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
740 ConcurrentRoot,
741 false,
742 null,
743 + null,
744 );
745 return {
746 _Scheduler: Scheduler,
@@ -766,6 +767,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
767 LegacyRoot,
768 false,
769 null,
770 + null,
771 );
772 return {
773 _Scheduler: Scheduler,
packages/react-reconciler/src/ReactFiber.new.js
+8 -1
@@ -422,12 +422,19 @@ export function resetWorkInProgress(workInProgress: Fiber, renderLanes: Lanes) {
422
423 export function createHostRootFiber(
424 tag: RootTag,
425 + isStrictMode: boolean,
426 concurrentUpdatesByDefaultOverride: null | boolean,
427 ): Fiber {
428 let mode;
429 if (tag === ConcurrentRoot) {
430 mode = ConcurrentMode;
430 - if (enableStrictEffects && createRootStrictEffectsByDefault) {
431 + if (isStrictMode === true) {
432 + mode |= StrictLegacyMode;
433 +
434 + if (enableStrictEffects) {
435 + mode |= StrictEffectsMode;
436 + }
437 + } else if (enableStrictEffects && createRootStrictEffectsByDefault) {
438 mode |= StrictLegacyMode | StrictEffectsMode;
439 }
440 if (
packages/react-reconciler/src/ReactFiber.old.js
+8 -1
@@ -422,12 +422,19 @@ export function resetWorkInProgress(workInProgress: Fiber, renderLanes: Lanes) {
422
423 export function createHostRootFiber(
424 tag: RootTag,
425 + isStrictMode: boolean,
426 concurrentUpdatesByDefaultOverride: null | boolean,
427 ): Fiber {
428 let mode;
429 if (tag === ConcurrentRoot) {
430 mode = ConcurrentMode;
430 - if (enableStrictEffects && createRootStrictEffectsByDefault) {
431 + if (isStrictMode === true) {
432 + mode |= StrictLegacyMode;
433 +
434 + if (enableStrictEffects) {
435 + mode |= StrictEffectsMode;
436 + }
437 + } else if (enableStrictEffects && createRootStrictEffectsByDefault) {
438 mode |= StrictLegacyMode | StrictEffectsMode;
439 }
440 if (
packages/react-reconciler/src/ReactFiberReconciler.new.js
+2
@@ -248,6 +248,7 @@ export function createContainer(
248 tag: RootTag,
249 hydrate: boolean,
250 hydrationCallbacks: null | SuspenseHydrationCallbacks,
251 + isStrictMode: boolean,
252 concurrentUpdatesByDefaultOverride: null | boolean,
253 ): OpaqueRoot {
254 return createFiberRoot(
@@ -255,6 +256,7 @@ export function createContainer(
256 tag,
257 hydrate,
258 hydrationCallbacks,
259 + isStrictMode,
260 concurrentUpdatesByDefaultOverride,
261 );
262 }
packages/react-reconciler/src/ReactFiberReconciler.old.js
+2
@@ -248,6 +248,7 @@ export function createContainer(
248 tag: RootTag,
249 hydrate: boolean,
250 hydrationCallbacks: null | SuspenseHydrationCallbacks,
251 + isStrictMode: boolean,
252 concurrentUpdatesByDefaultOverride: null | boolean,
253 ): OpaqueRoot {
254 return createFiberRoot(
@@ -255,6 +256,7 @@ export function createContainer(
256 tag,
257 hydrate,
258 hydrationCallbacks,
259 + isStrictMode,
260 concurrentUpdatesByDefaultOverride,
261 );
262 }
packages/react-reconciler/src/ReactFiberRoot.new.js
+2
@@ -98,6 +98,7 @@ export function createFiberRoot(
98 tag: RootTag,
99 hydrate: boolean,
100 hydrationCallbacks: null | SuspenseHydrationCallbacks,
101 + isStrictMode: boolean,
102 concurrentUpdatesByDefaultOverride: null | boolean,
103 ): FiberRoot {
104 const root: FiberRoot = (new FiberRootNode(containerInfo, tag, hydrate): any);
@@ -109,6 +110,7 @@ export function createFiberRoot(
110 // stateNode is any.
111 const uninitializedFiber = createHostRootFiber(
112 tag,
113 + isStrictMode,
114 concurrentUpdatesByDefaultOverride,
115 );
116 root.current = uninitializedFiber;
packages/react-reconciler/src/ReactFiberRoot.old.js
+2
@@ -98,6 +98,7 @@ export function createFiberRoot(
98 tag: RootTag,
99 hydrate: boolean,
100 hydrationCallbacks: null | SuspenseHydrationCallbacks,
101 + isStrictMode: boolean,
102 concurrentUpdatesByDefaultOverride: null | boolean,
103 ): FiberRoot {
104 const root: FiberRoot = (new FiberRootNode(containerInfo, tag, hydrate): any);
@@ -109,6 +110,7 @@ export function createFiberRoot(
110 // stateNode is any.
111 const uninitializedFiber = createHostRootFiber(
112 tag,
113 + isStrictMode,
114 concurrentUpdatesByDefaultOverride,
115 );
116 root.current = uninitializedFiber;
packages/react-test-renderer/src/ReactTestRenderer.js
+6
@@ -58,6 +58,7 @@ const {IsSomeRendererActing} = ReactSharedInternals;
58 type TestRendererOptions = {
59 createNodeMock: (element: React$Element<any>) => any,
60 unstable_isConcurrent: boolean,
61 + unstable_strictMode: boolean,
62 unstable_concurrentUpdatesByDefault: boolean,
63 ...
64 };
@@ -436,6 +437,7 @@ function propsMatch(props: Object, filter: Object): boolean {
437 function create(element: React$Element<any>, options: TestRendererOptions) {
438 let createNodeMock = defaultTestOptions.createNodeMock;
439 let isConcurrent = false;
440 + let isStrictMode = false;
441 let concurrentUpdatesByDefault = null;
442 if (typeof options === 'object' && options !== null) {
443 if (typeof options.createNodeMock === 'function') {
@@ -444,6 +446,9 @@ function create(element: React$Element<any>, options: TestRendererOptions) {
446 if (options.unstable_isConcurrent === true) {
447 isConcurrent = true;
448 }
449 + if (options.unstable_strictMode === true) {
450 + isStrictMode = true;
451 + }
452 if (allowConcurrentByDefault) {
453 if (options.unstable_concurrentUpdatesByDefault !== undefined) {
454 concurrentUpdatesByDefault =
@@ -461,6 +466,7 @@ function create(element: React$Element<any>, options: TestRendererOptions) {
466 isConcurrent ? ConcurrentRoot : LegacyRoot,
467 false,
468 null,
469 + isStrictMode,
470 concurrentUpdatesByDefault,
471 );
472 invariant(root != null, 'something went wrong');
packages/react/src/__tests__/ReactStrictMode-test.internal.js
+22
@@ -65,6 +65,28 @@ describe('ReactStrictMode', () => {
65 });
66
67 if (__DEV__) {
68 + // @gate experimental
69 + it('should support enabling strict mode via createRoot option', () => {
70 + act(() => {
71 + const container = document.createElement('div');
72 + const root = ReactDOM.createRoot(container, {
73 + unstable_strictMode: true,
74 + });
75 + root.render(<Component label="A" />);
76 + });
77 +
78 + expect(log).toEqual([
79 + 'A: render',
80 + 'A: render',
81 + 'A: useLayoutEffect mount',
82 + 'A: useEffect mount',
83 + 'A: useLayoutEffect unmount',
84 + 'A: useEffect unmount',
85 + 'A: useLayoutEffect mount',
86 + 'A: useEffect mount',
87 + ]);
88 + });
89 +
90 // @gate experimental
91 it('should include legacy + strict effects mode', () => {
92 act(() => {