@samitouri / QOS-React-2 / commits / 45c172d948

feat: honor displayName of context types (#18035)

* test: Add test for current behavior of displayName * feat: consider displayName of context types

Brian Vaughn committed Mar 4, 2020 at 14:54 UTC 45c172d948eee1a8533908267ec8be70bbb00c55
3 files changed +38 -2
packages/react/src/ReactContext.js
+5
@@ -120,6 +120,11 @@ export function createContext<T>(
120 return context.Consumer;
121 },
122 },
123 + displayName: {
124 + get() {
125 + return context.displayName;
126 + },
127 + },
128 });
129 // $FlowFixMe: Flow complains about missing properties because it doesn't understand defineProperty
130 context.Consumer = Consumer;
packages/react/src/__tests__/ReactContextValidator-test.js
+24
@@ -18,6 +18,7 @@
18 let PropTypes;
19 let React;
20 let ReactDOM;
21 +let ReactDOMServer;
22 let ReactTestUtils;
23
24 describe('ReactContextValidator', () => {
@@ -27,6 +28,7 @@ describe('ReactContextValidator', () => {
28 PropTypes = require('prop-types');
29 React = require('react');
30 ReactDOM = require('react-dom');
31 + ReactDOMServer = require('react-dom/server');
32 ReactTestUtils = require('react-dom/test-utils');
33 });
34
@@ -671,4 +673,26 @@ describe('ReactContextValidator', () => {
673 'Warning: ComponentB: Function components do not support contextType.',
674 );
675 });
676 +
677 + it('should honor a displayName if set on the context type', () => {
678 + const Context = React.createContext(null);
679 + Context.displayName = 'MyContextType';
680 + function Validator() {
681 + return null;
682 + }
683 + Validator.propTypes = {dontPassToSeeErrorStack: PropTypes.bool.isRequired};
684 +
685 + expect(() => {
686 + ReactDOMServer.renderToStaticMarkup(
687 + <Context.Provider>
688 + <Context.Consumer>{() => <Validator />}</Context.Consumer>
689 + </Context.Provider>,
690 + );
691 + }).toErrorDev(
692 + 'Warning: Failed prop type: The prop `dontPassToSeeErrorStack` is marked as required in `Validator`, but its value is `undefined`.\n' +
693 + ' in Validator (at **)\n' +
694 + ' in MyContextType.Consumer (at **)\n' +
695 + ' in MyContextType.Provider (at **)',
696 + );
697 + });
698 });
packages/shared/getComponentName.js
+9 -2
@@ -24,6 +24,7 @@ import {
24 REACT_BLOCK_TYPE,
25 } from 'shared/ReactSymbols';
26 import {refineResolvedLazyComponent} from 'shared/ReactLazyComponent';
27 +import type {ReactContext, ReactProviderType} from 'shared/ReactTypes';
28
29 function getWrappedName(
30 outerType: mixed,
@@ -37,6 +38,10 @@ function getWrappedName(
38 );
39 }
40
41 +function getContextName(type: ReactContext<any>) {
42 + return type.displayName || 'Context';
43 +}
44 +
45 function getComponentName(type: mixed): string | null {
46 if (type == null) {
47 // Host root, text node or just invalid type.
@@ -73,9 +78,11 @@ function getComponentName(type: mixed): string | null {
78 if (typeof type === 'object') {
79 switch (type.$$typeof) {
80 case REACT_CONTEXT_TYPE:
76 - return 'Context.Consumer';
81 + const context: ReactContext<any> = (type: any);
82 + return getContextName(context) + '.Consumer';
83 case REACT_PROVIDER_TYPE:
78 - return 'Context.Provider';
84 + const provider: ReactProviderType<any> = (type: any);
85 + return getContextName(provider._context) + '.Provider';
86 case REACT_FORWARD_REF_TYPE:
87 return getWrappedName(type, type.render, 'ForwardRef');
88 case REACT_MEMO_TYPE: