mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
14fd9630ee
Previously, `<Context>` was equivalent to `<Context.Consumer>`. However,
since the introduction of Hooks, the `<Context.Consumer>` API is rarely
used. The goal here is to make the common case cleaner:
```js
const ThemeContext = createContext('light')
function App() {
return (
<ThemeContext value="dark">
...
</ThemeContext>
)
}
function Button() {
const theme = use(ThemeContext)
// ...
}
```
This is technically a breaking change, but we've been warning about
rendering `<Context>` directly for several years by now, so it's
unlikely much code in the wild depends on the old behavior. [Proof that
it warns today (check
console).](https://codesandbox.io/p/sandbox/peaceful-nobel-pdxtfl)
---
**The relevant commit is 5696782b428a5ace96e66c1857e13249b6c07958.** It
switches `createContext` implementation so that `Context.Provider ===
Context`.
The main assumption that changed is that a Provider's fiber type is now
the context itself (rather than an intermediate object). Whereas a
Consumer's fiber type is now always an intermediate object (rather than
it being sometimes the context itself and sometimes an intermediate
object).
My methodology was to start with the relevant symbols, work tags, and
types, and work my way backwards to all usages.
This might break tooling that depends on inspecting React's internal
fields. I've added DevTools support in the second commit. This didn't
need explicit versioning—the structure tells us enough.
142 lines
4.1 KiB
JavaScript
142 lines
4.1 KiB
JavaScript
/**
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @flow
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
import {
|
|
REACT_CONTEXT_TYPE,
|
|
REACT_ELEMENT_TYPE,
|
|
REACT_FORWARD_REF_TYPE,
|
|
REACT_FRAGMENT_TYPE,
|
|
REACT_LAZY_TYPE,
|
|
REACT_MEMO_TYPE,
|
|
REACT_PORTAL_TYPE,
|
|
REACT_PROFILER_TYPE,
|
|
REACT_PROVIDER_TYPE,
|
|
REACT_CONSUMER_TYPE,
|
|
REACT_STRICT_MODE_TYPE,
|
|
REACT_SUSPENSE_TYPE,
|
|
REACT_SUSPENSE_LIST_TYPE,
|
|
} from 'shared/ReactSymbols';
|
|
import isValidElementType from 'shared/isValidElementType';
|
|
import {enableRenderableContext} from 'shared/ReactFeatureFlags';
|
|
|
|
export function typeOf(object: any): mixed {
|
|
if (typeof object === 'object' && object !== null) {
|
|
const $$typeof = object.$$typeof;
|
|
switch ($$typeof) {
|
|
case REACT_ELEMENT_TYPE:
|
|
const type = object.type;
|
|
|
|
switch (type) {
|
|
case REACT_FRAGMENT_TYPE:
|
|
case REACT_PROFILER_TYPE:
|
|
case REACT_STRICT_MODE_TYPE:
|
|
case REACT_SUSPENSE_TYPE:
|
|
case REACT_SUSPENSE_LIST_TYPE:
|
|
return type;
|
|
default:
|
|
const $$typeofType = type && type.$$typeof;
|
|
|
|
switch ($$typeofType) {
|
|
case REACT_CONTEXT_TYPE:
|
|
case REACT_FORWARD_REF_TYPE:
|
|
case REACT_LAZY_TYPE:
|
|
case REACT_MEMO_TYPE:
|
|
return $$typeofType;
|
|
case REACT_CONSUMER_TYPE:
|
|
if (enableRenderableContext) {
|
|
return $$typeofType;
|
|
}
|
|
// Fall through
|
|
case REACT_PROVIDER_TYPE:
|
|
if (!enableRenderableContext) {
|
|
return $$typeofType;
|
|
}
|
|
// Fall through
|
|
default:
|
|
return $$typeof;
|
|
}
|
|
}
|
|
case REACT_PORTAL_TYPE:
|
|
return $$typeof;
|
|
}
|
|
}
|
|
|
|
return undefined;
|
|
}
|
|
|
|
export const ContextConsumer: symbol = enableRenderableContext
|
|
? REACT_CONSUMER_TYPE
|
|
: REACT_CONTEXT_TYPE;
|
|
export const ContextProvider: symbol = enableRenderableContext
|
|
? REACT_CONTEXT_TYPE
|
|
: REACT_PROVIDER_TYPE;
|
|
export const Element = REACT_ELEMENT_TYPE;
|
|
export const ForwardRef = REACT_FORWARD_REF_TYPE;
|
|
export const Fragment = REACT_FRAGMENT_TYPE;
|
|
export const Lazy = REACT_LAZY_TYPE;
|
|
export const Memo = REACT_MEMO_TYPE;
|
|
export const Portal = REACT_PORTAL_TYPE;
|
|
export const Profiler = REACT_PROFILER_TYPE;
|
|
export const StrictMode = REACT_STRICT_MODE_TYPE;
|
|
export const Suspense = REACT_SUSPENSE_TYPE;
|
|
export const SuspenseList = REACT_SUSPENSE_LIST_TYPE;
|
|
|
|
export {isValidElementType};
|
|
|
|
export function isContextConsumer(object: any): boolean {
|
|
if (enableRenderableContext) {
|
|
return typeOf(object) === REACT_CONSUMER_TYPE;
|
|
} else {
|
|
return typeOf(object) === REACT_CONTEXT_TYPE;
|
|
}
|
|
}
|
|
export function isContextProvider(object: any): boolean {
|
|
if (enableRenderableContext) {
|
|
return typeOf(object) === REACT_CONTEXT_TYPE;
|
|
} else {
|
|
return typeOf(object) === REACT_PROVIDER_TYPE;
|
|
}
|
|
}
|
|
export function isElement(object: any): boolean {
|
|
return (
|
|
typeof object === 'object' &&
|
|
object !== null &&
|
|
object.$$typeof === REACT_ELEMENT_TYPE
|
|
);
|
|
}
|
|
export function isForwardRef(object: any): boolean {
|
|
return typeOf(object) === REACT_FORWARD_REF_TYPE;
|
|
}
|
|
export function isFragment(object: any): boolean {
|
|
return typeOf(object) === REACT_FRAGMENT_TYPE;
|
|
}
|
|
export function isLazy(object: any): boolean {
|
|
return typeOf(object) === REACT_LAZY_TYPE;
|
|
}
|
|
export function isMemo(object: any): boolean {
|
|
return typeOf(object) === REACT_MEMO_TYPE;
|
|
}
|
|
export function isPortal(object: any): boolean {
|
|
return typeOf(object) === REACT_PORTAL_TYPE;
|
|
}
|
|
export function isProfiler(object: any): boolean {
|
|
return typeOf(object) === REACT_PROFILER_TYPE;
|
|
}
|
|
export function isStrictMode(object: any): boolean {
|
|
return typeOf(object) === REACT_STRICT_MODE_TYPE;
|
|
}
|
|
export function isSuspense(object: any): boolean {
|
|
return typeOf(object) === REACT_SUSPENSE_TYPE;
|
|
}
|
|
export function isSuspenseList(object: any): boolean {
|
|
return typeOf(object) === REACT_SUSPENSE_LIST_TYPE;
|
|
}
|