From 555ece0cd14779abd5a1fc50f71625f9ada42bef Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Thu, 12 Jan 2023 13:17:15 +0100 Subject: [PATCH] Don't warn about concurrently rendering contexts if we finished rendering (#22797) Closes https://github.com/facebook/react/issues/22796 --- .../src/ReactFiberNewContext.js | 27 +++++++++++- .../src/__tests__/ReactNewContext-test.js | 42 +++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/packages/react-reconciler/src/ReactFiberNewContext.js b/packages/react-reconciler/src/ReactFiberNewContext.js index acaafbce15266..9e9abfb620798 100644 --- a/packages/react-reconciler/src/ReactFiberNewContext.js +++ b/packages/react-reconciler/src/ReactFiberNewContext.js @@ -49,6 +49,15 @@ import {REACT_SERVER_CONTEXT_DEFAULT_VALUE_NOT_LOADED} from 'shared/ReactSymbols const valueCursor: StackCursor = createCursor(null); +let rendererCursorDEV: StackCursor; +if (__DEV__) { + rendererCursorDEV = createCursor(null); +} +let renderer2CursorDEV: StackCursor; +if (__DEV__) { + renderer2CursorDEV = createCursor(null); +} + let rendererSigil; if (__DEV__) { // Use this to detect multiple renderers using the same context @@ -94,6 +103,8 @@ export function pushProvider( context._currentValue = nextValue; if (__DEV__) { + push(rendererCursorDEV, context._currentRenderer, providerFiber); + if ( context._currentRenderer !== undefined && context._currentRenderer !== null && @@ -111,6 +122,8 @@ export function pushProvider( context._currentValue2 = nextValue; if (__DEV__) { + push(renderer2CursorDEV, context._currentRenderer2, providerFiber); + if ( context._currentRenderer2 !== undefined && context._currentRenderer2 !== null && @@ -131,7 +144,7 @@ export function popProvider( providerFiber: Fiber, ): void { const currentValue = valueCursor.current; - pop(valueCursor, providerFiber); + if (isPrimaryRenderer) { if ( enableServerContext && @@ -141,6 +154,11 @@ export function popProvider( } else { context._currentValue = currentValue; } + if (__DEV__) { + const currentRenderer = rendererCursorDEV.current; + pop(rendererCursorDEV, providerFiber); + context._currentRenderer = currentRenderer; + } } else { if ( enableServerContext && @@ -150,7 +168,14 @@ export function popProvider( } else { context._currentValue2 = currentValue; } + if (__DEV__) { + const currentRenderer2 = renderer2CursorDEV.current; + pop(renderer2CursorDEV, providerFiber); + context._currentRenderer2 = currentRenderer2; + } } + + pop(valueCursor, providerFiber); } export function scheduleContextWorkOnParentPath( diff --git a/packages/react-reconciler/src/__tests__/ReactNewContext-test.js b/packages/react-reconciler/src/__tests__/ReactNewContext-test.js index 9bfc2cbb549e9..7aacafab8c3af 100644 --- a/packages/react-reconciler/src/__tests__/ReactNewContext-test.js +++ b/packages/react-reconciler/src/__tests__/ReactNewContext-test.js @@ -874,6 +874,48 @@ describe('ReactNewContext', () => { } }); + it('does not warn if multiple renderers use the same context sequentially', () => { + spyOnDev(console, 'error'); + const Context = React.createContext(0); + + function Foo(props) { + Scheduler.unstable_yieldValue('Foo'); + return null; + } + + function App(props) { + return ( + + + + + ); + } + + if (gate(flags => flags.enableSyncDefaultUpdates)) { + React.startTransition(() => { + ReactNoop.render(); + }); + } else { + ReactNoop.render(); + } + expect(Scheduler).toFlushAndYield(['Foo', 'Foo']); + + // Get a new copy of ReactNoop + jest.resetModules(); + React = require('react'); + ReactNoop = require('react-noop-renderer'); + Scheduler = require('scheduler'); + + // Render the provider again using a different renderer + ReactNoop.render(); + expect(Scheduler).toFlushAndYield(['Foo', 'Foo']); + + if (__DEV__) { + expect(console.error).not.toHaveBeenCalled(); + } + }); + it('provider bails out if children and value are unchanged (like sCU)', () => { const Context = React.createContext(0);