1. /**
    
  2.  * Copyright (c) Meta Platforms, Inc. and affiliates.
    
  3.  *
    
  4.  * This source code is licensed under the MIT license found in the
    
  5.  * LICENSE file in the root directory of this source tree.
    
  6.  *
    
  7.  * @flow
    
  8.  */
    
  9. 
    
  10. import * as React from 'react';
    
  11. import {createContext, Component, useContext, useState} from 'react';
    
  12. import PropTypes from 'prop-types';
    
  13. 
    
  14. import type {ReactContext} from 'shared/ReactTypes';
    
  15. 
    
  16. function someNamedFunction() {}
    
  17. 
    
  18. function formatContextForDisplay(name: string, value: any | string) {
    
  19.   return (
    
  20.     <li>
    
  21.       {name}: <pre>{JSON.stringify(value, null, 2)}</pre>
    
  22.     </li>
    
  23.   );
    
  24. }
    
  25. 
    
  26. const contextData = {
    
  27.   array: ['first', 'second', 'third'],
    
  28.   bool: true,
    
  29.   func: someNamedFunction,
    
  30.   number: 123,
    
  31.   object: {outer: {inner: {}}},
    
  32.   string: 'abc',
    
  33.   symbol: Symbol.for('symbol'),
    
  34.   null: null,
    
  35.   undefined: undefined,
    
  36. };
    
  37. 
    
  38. class LegacyContextProvider extends Component<any> {
    
  39.   static childContextTypes: {
    
  40.     array: any,
    
  41.     bool: any,
    
  42.     func: any,
    
  43.     null: any,
    
  44.     number: any,
    
  45.     object: any,
    
  46.     string: any,
    
  47.     symbol: any,
    
  48.     undefined: any,
    
  49.   } = {
    
  50.     array: PropTypes.array,
    
  51.     bool: PropTypes.bool,
    
  52.     func: PropTypes.func,
    
  53.     number: PropTypes.number,
    
  54.     object: PropTypes.object,
    
  55.     string: PropTypes.string,
    
  56.     symbol: PropTypes.symbol,
    
  57.     null: PropTypes.any,
    
  58.     undefined: PropTypes.any,
    
  59.   };
    
  60. 
    
  61.   getChildContext(): {
    
  62.     array: Array<string>,
    
  63.     bool: boolean,
    
  64.     func: () => void,
    
  65.     null: null,
    
  66.     number: number,
    
  67.     object: {outer: {inner: {...}}},
    
  68.     string: string,
    
  69.     symbol: symbol,
    
  70.     undefined: void,
    
  71.   } {
    
  72.     return contextData;
    
  73.   }
    
  74. 
    
  75.   render(): any {
    
  76.     return this.props.children;
    
  77.   }
    
  78. }
    
  79. 
    
  80. class LegacyContextConsumer extends Component<any> {
    
  81.   static contextTypes: {
    
  82.     array: any,
    
  83.     bool: any,
    
  84.     func: any,
    
  85.     null: any,
    
  86.     number: any,
    
  87.     object: any,
    
  88.     string: any,
    
  89.     symbol: any,
    
  90.     undefined: any,
    
  91.   } = {
    
  92.     array: PropTypes.array,
    
  93.     bool: PropTypes.bool,
    
  94.     func: PropTypes.func,
    
  95.     number: PropTypes.number,
    
  96.     object: PropTypes.object,
    
  97.     string: PropTypes.string,
    
  98.     symbol: PropTypes.symbol,
    
  99.     null: PropTypes.any,
    
  100.     undefined: PropTypes.any,
    
  101.   };
    
  102. 
    
  103.   render(): any {
    
  104.     return formatContextForDisplay('LegacyContextConsumer', this.context);
    
  105.   }
    
  106. }
    
  107. 
    
  108. class LegacyContextProviderWithUpdates extends Component<any> {
    
  109.   constructor(props: any) {
    
  110.     super(props);
    
  111.     this.state = {type: 'desktop'};
    
  112.   }
    
  113. 
    
  114.   getChildContext(): {type: any} {
    
  115.     return {type: this.state.type};
    
  116.   }
    
  117. 
    
  118.   // $FlowFixMe[missing-local-annot]
    
  119.   handleChange = event => {
    
  120.     this.setState({type: event.target.value});
    
  121.   };
    
  122. 
    
  123.   render(): any {
    
  124.     return (
    
  125.       <>
    
  126.         <LegacyFunctionalContextConsumer />
    
  127.         <div>
    
  128.           <input value={this.state.type} onChange={this.handleChange} />
    
  129.         </div>
    
  130.       </>
    
  131.     );
    
  132.   }
    
  133. }
    
  134. 
    
  135. LegacyContextProviderWithUpdates.childContextTypes = {
    
  136.   type: PropTypes.string,
    
  137. };
    
  138. 
    
  139. // $FlowFixMe[missing-local-annot]
    
  140. function LegacyFunctionalContextConsumer(props: any, context) {
    
  141.   return formatContextForDisplay('LegacyFunctionContextConsumer', context.type);
    
  142. }
    
  143. LegacyFunctionalContextConsumer.contextTypes = {
    
  144.   type: PropTypes.string,
    
  145. };
    
  146. 
    
  147. const ModernContext = createContext();
    
  148. ModernContext.displayName = 'ModernContext';
    
  149. const ArrayContext = createContext(contextData.array);
    
  150. ArrayContext.displayName = 'ArrayContext';
    
  151. const BoolContext = createContext(contextData.bool);
    
  152. BoolContext.displayName = 'BoolContext';
    
  153. const FuncContext = createContext(contextData.func);
    
  154. FuncContext.displayName = 'FuncContext';
    
  155. const NumberContext = createContext(contextData.number);
    
  156. NumberContext.displayName = 'NumberContext';
    
  157. const StringContext = createContext(contextData.string);
    
  158. StringContext.displayName = 'StringContext';
    
  159. const SymbolContext = createContext(contextData.symbol);
    
  160. SymbolContext.displayName = 'SymbolContext';
    
  161. const NullContext = createContext(null);
    
  162. NullContext.displayName = 'NullContext';
    
  163. const UndefinedContext = createContext(undefined);
    
  164. UndefinedContext.displayName = 'UndefinedContext';
    
  165. 
    
  166. class ModernContextType extends Component<any> {
    
  167.   static contextType: ReactContext<void> = ModernContext;
    
  168. 
    
  169.   render(): any {
    
  170.     return formatContextForDisplay('ModernContextType', this.context);
    
  171.   }
    
  172. }
    
  173. 
    
  174. function FunctionalContextConsumer() {
    
  175.   const value = useContext(StringContext);
    
  176.   return formatContextForDisplay('FunctionalContextConsumer', value);
    
  177. }
    
  178. 
    
  179. const StringContextWithUpdates = createContext({
    
  180.   string: contextData.string,
    
  181.   setString: (string: string) => {},
    
  182. });
    
  183. const StringContextWithUpdates2 = createContext({
    
  184.   string2: contextData.string,
    
  185.   setString2: (string: string) => {},
    
  186. });
    
  187. 
    
  188. function FunctionalContextProviderWithContextUpdates() {
    
  189.   const [string, setString] = useState(contextData.string);
    
  190.   const [string2, setString2] = useState(contextData.string);
    
  191.   const value = {string, setString};
    
  192.   const value2 = {string2, setString2};
    
  193. 
    
  194.   return (
    
  195.     <StringContextWithUpdates.Provider value={value}>
    
  196.       <StringContextWithUpdates2.Provider value={value2}>
    
  197.         <FunctionalContextConsumerWithContextUpdates />
    
  198.       </StringContextWithUpdates2.Provider>
    
  199.     </StringContextWithUpdates.Provider>
    
  200.   );
    
  201. }
    
  202. 
    
  203. function FunctionalContextConsumerWithContextUpdates() {
    
  204.   const {string, setString} = useContext(StringContextWithUpdates);
    
  205.   const {string2, setString2} = useContext(StringContextWithUpdates2);
    
  206.   const [state, setState] = useState('state');
    
  207. 
    
  208.   // $FlowFixMe[missing-local-annot]
    
  209.   const handleChange = e => setString(e.target.value);
    
  210.   // $FlowFixMe[missing-local-annot]
    
  211.   const handleChange2 = e => setString2(e.target.value);
    
  212. 
    
  213.   return (
    
  214.     <>
    
  215.       {formatContextForDisplay(
    
  216.         'FunctionalContextConsumerWithUpdates',
    
  217.         `context: ${string}, context 2: ${string2}`,
    
  218.       )}
    
  219.       <div>
    
  220.         context: <input value={string} onChange={handleChange} />
    
  221.       </div>
    
  222.       <div>
    
  223.         context 2: <input value={string2} onChange={handleChange2} />
    
  224.       </div>
    
  225.       <div>
    
  226.         {state}
    
  227.         <div>
    
  228.           test state:{' '}
    
  229.           <input value={state} onChange={e => setState(e.target.value)} />
    
  230.         </div>
    
  231.       </div>
    
  232.     </>
    
  233.   );
    
  234. }
    
  235. 
    
  236. class ModernClassContextProviderWithUpdates extends Component<any> {
    
  237.   constructor(props: any) {
    
  238.     super(props);
    
  239.     this.setString = string => {
    
  240.       this.setState({string});
    
  241.     };
    
  242. 
    
  243.     this.state = {
    
  244.       string: contextData.string,
    
  245.       setString: this.setString,
    
  246.     };
    
  247.   }
    
  248. 
    
  249.   render(): any {
    
  250.     return (
    
  251.       <StringContextWithUpdates.Provider value={this.state}>
    
  252.         <ModernClassContextConsumerWithUpdates />
    
  253.       </StringContextWithUpdates.Provider>
    
  254.     );
    
  255.   }
    
  256. }
    
  257. 
    
  258. class ModernClassContextConsumerWithUpdates extends Component<any> {
    
  259.   render(): any {
    
  260.     return (
    
  261.       <StringContextWithUpdates.Consumer>
    
  262.         {({string, setString}: {string: string, setString: string => void}) => (
    
  263.           <>
    
  264.             {formatContextForDisplay(
    
  265.               'ModernClassContextConsumerWithUpdates',
    
  266.               string,
    
  267.             )}
    
  268.             <input value={string} onChange={e => setString(e.target.value)} />
    
  269.           </>
    
  270.         )}
    
  271.       </StringContextWithUpdates.Consumer>
    
  272.     );
    
  273.   }
    
  274. }
    
  275. 
    
  276. export default function Contexts(): React.Node {
    
  277.   return (
    
  278.     <div>
    
  279.       <h1>Contexts</h1>
    
  280.       <ul>
    
  281.         <LegacyContextProvider>
    
  282.           <LegacyContextConsumer />
    
  283.         </LegacyContextProvider>
    
  284.         <LegacyContextProviderWithUpdates />
    
  285.         <ModernContext.Provider value={contextData}>
    
  286.           <ModernContext.Consumer>
    
  287.             {(value: $FlowFixMe) =>
    
  288.               formatContextForDisplay('ModernContext.Consumer', value)
    
  289.             }
    
  290.           </ModernContext.Consumer>
    
  291.           <ModernContextType />
    
  292.         </ModernContext.Provider>
    
  293.         <FunctionalContextConsumer />
    
  294.         <FunctionalContextProviderWithContextUpdates />
    
  295.         <ModernClassContextProviderWithUpdates />
    
  296.         <ArrayContext.Consumer>
    
  297.           {(value: $FlowFixMe) =>
    
  298.             formatContextForDisplay('ArrayContext.Consumer', value)
    
  299.           }
    
  300.         </ArrayContext.Consumer>
    
  301.         <BoolContext.Consumer>
    
  302.           {(value: $FlowFixMe) =>
    
  303.             formatContextForDisplay('BoolContext.Consumer', value)
    
  304.           }
    
  305.         </BoolContext.Consumer>
    
  306.         <FuncContext.Consumer>
    
  307.           {(value: $FlowFixMe) =>
    
  308.             formatContextForDisplay('FuncContext.Consumer', value)
    
  309.           }
    
  310.         </FuncContext.Consumer>
    
  311.         <NumberContext.Consumer>
    
  312.           {(value: $FlowFixMe) =>
    
  313.             formatContextForDisplay('NumberContext.Consumer', value)
    
  314.           }
    
  315.         </NumberContext.Consumer>
    
  316.         <StringContext.Consumer>
    
  317.           {(value: $FlowFixMe) =>
    
  318.             formatContextForDisplay('StringContext.Consumer', value)
    
  319.           }
    
  320.         </StringContext.Consumer>
    
  321.         <SymbolContext.Consumer>
    
  322.           {(value: $FlowFixMe) =>
    
  323.             formatContextForDisplay('SymbolContext.Consumer', value)
    
  324.           }
    
  325.         </SymbolContext.Consumer>
    
  326.         <NullContext.Consumer>
    
  327.           {(value: $FlowFixMe) =>
    
  328.             formatContextForDisplay('NullContext.Consumer', value)
    
  329.           }
    
  330.         </NullContext.Consumer>
    
  331.         <UndefinedContext.Consumer>
    
  332.           {(value: $FlowFixMe) =>
    
  333.             formatContextForDisplay('UndefinedContext.Consumer', value)
    
  334.           }
    
  335.         </UndefinedContext.Consumer>
    
  336.       </ul>
    
  337.     </div>
    
  338.   );
    
  339. }