From 4aaae58d7704448dee4a1b9e46d1fa436c6020bc Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Wed, 13 Dec 2017 19:11:07 -0800 Subject: [PATCH] Store nearest provider on context object --- .../src/server/ReactPartialRenderer.js | 29 +++++++++---------- .../src/ReactFiberBeginWork.js | 4 +-- .../src/ReactFiberNewContext.js | 23 ++++++++------- packages/shared/ReactContext.js | 1 + packages/shared/ReactTypes.js | 3 +- 5 files changed, 29 insertions(+), 31 deletions(-) diff --git a/packages/react-dom/src/server/ReactPartialRenderer.js b/packages/react-dom/src/server/ReactPartialRenderer.js index 552a1ac3aa69e..934b1d9b4ac4a 100644 --- a/packages/react-dom/src/server/ReactPartialRenderer.js +++ b/packages/react-dom/src/server/ReactPartialRenderer.js @@ -124,33 +124,30 @@ if (__DEV__) { } // Context (new API) -let providerStack: Array> = []; // Stack of provider objects +let providerStack: Array> = []; // Stack of provider objects let index = -1; export function pushProvider(provider: ReactProvider): void { index += 1; providerStack[index] = provider; + const context: ReactContext = provider.type.context; + context.currentProvider = provider; } export function popProvider(provider: ReactProvider): void { if (__DEV__) { warning(index > -1 && provider === providerStack[index], 'Unexpected pop.'); } + // $FlowFixMe - Intentionally unsound providerStack[index] = null; index -= 1; -} - -// Find the nearest matching provider -export function getProvider( - context: ReactContext, -): ReactProvider | null { - for (let i = index; i > -1; i--) { - const provider = providerStack[i]; - if (provider.type.context === context) { - return provider; - } + const context: ReactContext = provider.type.context; + if (index < 0) { + context.currentProvider = null; + } else { + const previousProvider = providerStack[index]; + context.currentProvider = previousProvider; } - return null; } let didWarnDefaultInputValue = false; @@ -731,7 +728,7 @@ class ReactDOMServerRenderer { if (typeof elementType === 'object' && elementType !== null) { switch (elementType.$$typeof) { case REACT_PROVIDER_TYPE: { - const provider: ReactProvider = nextChild; + const provider: ReactProvider = (nextChild: any); const nextProps = provider.props; const nextChildren = toArray(nextProps.children); const frame: Frame = { @@ -752,10 +749,10 @@ class ReactDOMServerRenderer { return ''; } case REACT_CONSUMER_TYPE: { - const consumer: ReactConsumer = nextChild; + const consumer: ReactConsumer = (nextChild: any); const nextProps = consumer.props; - const provider = getProvider(consumer.type.context); + const provider = consumer.type.context.currentProvider; let nextValue; if (provider === null) { // Detached consumer diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.js b/packages/react-reconciler/src/ReactFiberBeginWork.js index 4c568e94f5e6e..c5aba975c3ede 100644 --- a/packages/react-reconciler/src/ReactFiberBeginWork.js +++ b/packages/react-reconciler/src/ReactFiberBeginWork.js @@ -66,7 +66,7 @@ import { pushTopLevelContextObject, invalidateContextProvider, } from './ReactFiberContext'; -import {pushProvider, getProvider} from './ReactFiberNewContext'; +import {pushProvider} from './ReactFiberNewContext'; import {NoWork, Never} from './ReactFiberExpirationTime'; let warnedAboutStatelessRefs; @@ -755,7 +755,7 @@ export default function( const oldProps = workInProgress.memoizedProps; // Get the nearest ancestor provider. - const providerFiber: Fiber | null = getProvider(context); + const providerFiber: Fiber | null = context.currentProvider; let newValue; let valueDidChange; diff --git a/packages/react-reconciler/src/ReactFiberNewContext.js b/packages/react-reconciler/src/ReactFiberNewContext.js index bf6a24943c63e..ef132204b602d 100644 --- a/packages/react-reconciler/src/ReactFiberNewContext.js +++ b/packages/react-reconciler/src/ReactFiberNewContext.js @@ -18,6 +18,8 @@ let index = -1; export function pushProvider(providerFiber: Fiber): void { index += 1; stack[index] = providerFiber; + const context: ReactContext = providerFiber.type.context; + context.currentProvider = providerFiber; } export function popProvider(providerFiber: Fiber): void { @@ -26,21 +28,20 @@ export function popProvider(providerFiber: Fiber): void { } stack[index] = null; index -= 1; -} - -// Find the nearest matching provider -export function getProvider(context: ReactContext): Fiber | null { - for (let i = index; i > -1; i--) { - const provider = stack[i]; - if (provider.type.context === context) { - return provider; - } + const context: ReactContext = providerFiber.type.context; + if (index < 0) { + context.currentProvider = null; + } else { + const previousProviderFiber = stack[index]; + context.currentProvider = previousProviderFiber; } - return null; } export function resetProviderStack(): void { for (let i = index; i > -1; i--) { - stack[i] = null; + const providerFiber = stack[i]; + const context: ReactContext = providerFiber.type.context; + context.currentProvider = null; + stack[i] = undefined; } } diff --git a/packages/shared/ReactContext.js b/packages/shared/ReactContext.js index 52cf550985bfe..f1af0371bdf53 100644 --- a/packages/shared/ReactContext.js +++ b/packages/shared/ReactContext.js @@ -53,6 +53,7 @@ export function createContext(defaultValue: T): ReactContext { }; }, defaultValue, + currentProvider: null, }; providerType = { diff --git a/packages/shared/ReactTypes.js b/packages/shared/ReactTypes.js index 8d9faf94be125..e6ef0332a1665 100644 --- a/packages/shared/ReactTypes.js +++ b/packages/shared/ReactTypes.js @@ -1,5 +1,3 @@ -import {Symbol} from './node_modules/typescript/lib/typescript'; - /** * Copyright (c) 2014-present, Facebook, Inc. * @@ -88,6 +86,7 @@ export type ReactContext = { provide(value: T, children: ReactNodeList, key?: string): ReactProvider, consume(render: (value: T) => ReactNodeList, key?: string): ReactConsumer, defaultValue: T, + currentProvider: any, // Fiber | null }; export type ReactPortal = {