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 type {Fiber} from './ReactInternalTypes';
    
  11. 
    
  12. import {
    
  13.   resetCurrentFiber as resetCurrentDebugFiberInDEV,
    
  14.   setCurrentFiber as setCurrentDebugFiberInDEV,
    
  15. } from './ReactCurrentFiber';
    
  16. import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber';
    
  17. import {StrictLegacyMode} from './ReactTypeOfMode';
    
  18. 
    
  19. type FiberArray = Array<Fiber>;
    
  20. type FiberToFiberComponentsMap = Map<Fiber, FiberArray>;
    
  21. 
    
  22. const ReactStrictModeWarnings = {
    
  23.   recordUnsafeLifecycleWarnings: (fiber: Fiber, instance: any): void => {},
    
  24.   flushPendingUnsafeLifecycleWarnings: (): void => {},
    
  25.   recordLegacyContextWarning: (fiber: Fiber, instance: any): void => {},
    
  26.   flushLegacyContextWarning: (): void => {},
    
  27.   discardPendingWarnings: (): void => {},
    
  28. };
    
  29. 
    
  30. if (__DEV__) {
    
  31.   const findStrictRoot = (fiber: Fiber): Fiber | null => {
    
  32.     let maybeStrictRoot = null;
    
  33. 
    
  34.     let node: null | Fiber = fiber;
    
  35.     while (node !== null) {
    
  36.       if (node.mode & StrictLegacyMode) {
    
  37.         maybeStrictRoot = node;
    
  38.       }
    
  39.       node = node.return;
    
  40.     }
    
  41. 
    
  42.     return maybeStrictRoot;
    
  43.   };
    
  44. 
    
  45.   const setToSortedString = (set: Set<string>) => {
    
  46.     const array = [];
    
  47.     set.forEach(value => {
    
  48.       array.push(value);
    
  49.     });
    
  50.     return array.sort().join(', ');
    
  51.   };
    
  52. 
    
  53.   let pendingComponentWillMountWarnings: Array<Fiber> = [];
    
  54.   let pendingUNSAFE_ComponentWillMountWarnings: Array<Fiber> = [];
    
  55.   let pendingComponentWillReceivePropsWarnings: Array<Fiber> = [];
    
  56.   let pendingUNSAFE_ComponentWillReceivePropsWarnings: Array<Fiber> = [];
    
  57.   let pendingComponentWillUpdateWarnings: Array<Fiber> = [];
    
  58.   let pendingUNSAFE_ComponentWillUpdateWarnings: Array<Fiber> = [];
    
  59. 
    
  60.   // Tracks components we have already warned about.
    
  61.   const didWarnAboutUnsafeLifecycles = new Set<mixed>();
    
  62. 
    
  63.   ReactStrictModeWarnings.recordUnsafeLifecycleWarnings = (
    
  64.     fiber: Fiber,
    
  65.     instance: any,
    
  66.   ) => {
    
  67.     // Dedupe strategy: Warn once per component.
    
  68.     if (didWarnAboutUnsafeLifecycles.has(fiber.type)) {
    
  69.       return;
    
  70.     }
    
  71. 
    
  72.     if (
    
  73.       typeof instance.componentWillMount === 'function' &&
    
  74.       // Don't warn about react-lifecycles-compat polyfilled components.
    
  75.       instance.componentWillMount.__suppressDeprecationWarning !== true
    
  76.     ) {
    
  77.       pendingComponentWillMountWarnings.push(fiber);
    
  78.     }
    
  79. 
    
  80.     if (
    
  81.       fiber.mode & StrictLegacyMode &&
    
  82.       typeof instance.UNSAFE_componentWillMount === 'function'
    
  83.     ) {
    
  84.       pendingUNSAFE_ComponentWillMountWarnings.push(fiber);
    
  85.     }
    
  86. 
    
  87.     if (
    
  88.       typeof instance.componentWillReceiveProps === 'function' &&
    
  89.       instance.componentWillReceiveProps.__suppressDeprecationWarning !== true
    
  90.     ) {
    
  91.       pendingComponentWillReceivePropsWarnings.push(fiber);
    
  92.     }
    
  93. 
    
  94.     if (
    
  95.       fiber.mode & StrictLegacyMode &&
    
  96.       typeof instance.UNSAFE_componentWillReceiveProps === 'function'
    
  97.     ) {
    
  98.       pendingUNSAFE_ComponentWillReceivePropsWarnings.push(fiber);
    
  99.     }
    
  100. 
    
  101.     if (
    
  102.       typeof instance.componentWillUpdate === 'function' &&
    
  103.       instance.componentWillUpdate.__suppressDeprecationWarning !== true
    
  104.     ) {
    
  105.       pendingComponentWillUpdateWarnings.push(fiber);
    
  106.     }
    
  107. 
    
  108.     if (
    
  109.       fiber.mode & StrictLegacyMode &&
    
  110.       typeof instance.UNSAFE_componentWillUpdate === 'function'
    
  111.     ) {
    
  112.       pendingUNSAFE_ComponentWillUpdateWarnings.push(fiber);
    
  113.     }
    
  114.   };
    
  115. 
    
  116.   ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings = () => {
    
  117.     // We do an initial pass to gather component names
    
  118.     const componentWillMountUniqueNames = new Set<string>();
    
  119.     if (pendingComponentWillMountWarnings.length > 0) {
    
  120.       pendingComponentWillMountWarnings.forEach(fiber => {
    
  121.         componentWillMountUniqueNames.add(
    
  122.           getComponentNameFromFiber(fiber) || 'Component',
    
  123.         );
    
  124.         didWarnAboutUnsafeLifecycles.add(fiber.type);
    
  125.       });
    
  126.       pendingComponentWillMountWarnings = [];
    
  127.     }
    
  128. 
    
  129.     const UNSAFE_componentWillMountUniqueNames = new Set<string>();
    
  130.     if (pendingUNSAFE_ComponentWillMountWarnings.length > 0) {
    
  131.       pendingUNSAFE_ComponentWillMountWarnings.forEach(fiber => {
    
  132.         UNSAFE_componentWillMountUniqueNames.add(
    
  133.           getComponentNameFromFiber(fiber) || 'Component',
    
  134.         );
    
  135.         didWarnAboutUnsafeLifecycles.add(fiber.type);
    
  136.       });
    
  137.       pendingUNSAFE_ComponentWillMountWarnings = [];
    
  138.     }
    
  139. 
    
  140.     const componentWillReceivePropsUniqueNames = new Set<string>();
    
  141.     if (pendingComponentWillReceivePropsWarnings.length > 0) {
    
  142.       pendingComponentWillReceivePropsWarnings.forEach(fiber => {
    
  143.         componentWillReceivePropsUniqueNames.add(
    
  144.           getComponentNameFromFiber(fiber) || 'Component',
    
  145.         );
    
  146.         didWarnAboutUnsafeLifecycles.add(fiber.type);
    
  147.       });
    
  148. 
    
  149.       pendingComponentWillReceivePropsWarnings = [];
    
  150.     }
    
  151. 
    
  152.     const UNSAFE_componentWillReceivePropsUniqueNames = new Set<string>();
    
  153.     if (pendingUNSAFE_ComponentWillReceivePropsWarnings.length > 0) {
    
  154.       pendingUNSAFE_ComponentWillReceivePropsWarnings.forEach(fiber => {
    
  155.         UNSAFE_componentWillReceivePropsUniqueNames.add(
    
  156.           getComponentNameFromFiber(fiber) || 'Component',
    
  157.         );
    
  158.         didWarnAboutUnsafeLifecycles.add(fiber.type);
    
  159.       });
    
  160. 
    
  161.       pendingUNSAFE_ComponentWillReceivePropsWarnings = [];
    
  162.     }
    
  163. 
    
  164.     const componentWillUpdateUniqueNames = new Set<string>();
    
  165.     if (pendingComponentWillUpdateWarnings.length > 0) {
    
  166.       pendingComponentWillUpdateWarnings.forEach(fiber => {
    
  167.         componentWillUpdateUniqueNames.add(
    
  168.           getComponentNameFromFiber(fiber) || 'Component',
    
  169.         );
    
  170.         didWarnAboutUnsafeLifecycles.add(fiber.type);
    
  171.       });
    
  172. 
    
  173.       pendingComponentWillUpdateWarnings = [];
    
  174.     }
    
  175. 
    
  176.     const UNSAFE_componentWillUpdateUniqueNames = new Set<string>();
    
  177.     if (pendingUNSAFE_ComponentWillUpdateWarnings.length > 0) {
    
  178.       pendingUNSAFE_ComponentWillUpdateWarnings.forEach(fiber => {
    
  179.         UNSAFE_componentWillUpdateUniqueNames.add(
    
  180.           getComponentNameFromFiber(fiber) || 'Component',
    
  181.         );
    
  182.         didWarnAboutUnsafeLifecycles.add(fiber.type);
    
  183.       });
    
  184. 
    
  185.       pendingUNSAFE_ComponentWillUpdateWarnings = [];
    
  186.     }
    
  187. 
    
  188.     // Finally, we flush all the warnings
    
  189.     // UNSAFE_ ones before the deprecated ones, since they'll be 'louder'
    
  190.     if (UNSAFE_componentWillMountUniqueNames.size > 0) {
    
  191.       const sortedNames = setToSortedString(
    
  192.         UNSAFE_componentWillMountUniqueNames,
    
  193.       );
    
  194.       console.error(
    
  195.         'Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. ' +
    
  196.           'See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n' +
    
  197.           '* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' +
    
  198.           '\nPlease update the following components: %s',
    
  199.         sortedNames,
    
  200.       );
    
  201.     }
    
  202. 
    
  203.     if (UNSAFE_componentWillReceivePropsUniqueNames.size > 0) {
    
  204.       const sortedNames = setToSortedString(
    
  205.         UNSAFE_componentWillReceivePropsUniqueNames,
    
  206.       );
    
  207.       console.error(
    
  208.         'Using UNSAFE_componentWillReceiveProps in strict mode is not recommended ' +
    
  209.           'and may indicate bugs in your code. ' +
    
  210.           'See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n' +
    
  211.           '* Move data fetching code or side effects to componentDidUpdate.\n' +
    
  212.           "* If you're updating state whenever props change, " +
    
  213.           'refactor your code to use memoization techniques or move it to ' +
    
  214.           'static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state\n' +
    
  215.           '\nPlease update the following components: %s',
    
  216.         sortedNames,
    
  217.       );
    
  218.     }
    
  219. 
    
  220.     if (UNSAFE_componentWillUpdateUniqueNames.size > 0) {
    
  221.       const sortedNames = setToSortedString(
    
  222.         UNSAFE_componentWillUpdateUniqueNames,
    
  223.       );
    
  224.       console.error(
    
  225.         'Using UNSAFE_componentWillUpdate in strict mode is not recommended ' +
    
  226.           'and may indicate bugs in your code. ' +
    
  227.           'See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n' +
    
  228.           '* Move data fetching code or side effects to componentDidUpdate.\n' +
    
  229.           '\nPlease update the following components: %s',
    
  230.         sortedNames,
    
  231.       );
    
  232.     }
    
  233. 
    
  234.     if (componentWillMountUniqueNames.size > 0) {
    
  235.       const sortedNames = setToSortedString(componentWillMountUniqueNames);
    
  236. 
    
  237.       console.warn(
    
  238.         'componentWillMount has been renamed, and is not recommended for use. ' +
    
  239.           'See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n' +
    
  240.           '* Move code with side effects to componentDidMount, and set initial state in the constructor.\n' +
    
  241.           '* Rename componentWillMount to UNSAFE_componentWillMount to suppress ' +
    
  242.           'this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. ' +
    
  243.           'To rename all deprecated lifecycles to their new names, you can run ' +
    
  244.           '`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' +
    
  245.           '\nPlease update the following components: %s',
    
  246.         sortedNames,
    
  247.       );
    
  248.     }
    
  249. 
    
  250.     if (componentWillReceivePropsUniqueNames.size > 0) {
    
  251.       const sortedNames = setToSortedString(
    
  252.         componentWillReceivePropsUniqueNames,
    
  253.       );
    
  254. 
    
  255.       console.warn(
    
  256.         'componentWillReceiveProps has been renamed, and is not recommended for use. ' +
    
  257.           'See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n' +
    
  258.           '* Move data fetching code or side effects to componentDidUpdate.\n' +
    
  259.           "* If you're updating state whenever props change, refactor your " +
    
  260.           'code to use memoization techniques or move it to ' +
    
  261.           'static getDerivedStateFromProps. Learn more at: https://reactjs.org/link/derived-state\n' +
    
  262.           '* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress ' +
    
  263.           'this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. ' +
    
  264.           'To rename all deprecated lifecycles to their new names, you can run ' +
    
  265.           '`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' +
    
  266.           '\nPlease update the following components: %s',
    
  267.         sortedNames,
    
  268.       );
    
  269.     }
    
  270. 
    
  271.     if (componentWillUpdateUniqueNames.size > 0) {
    
  272.       const sortedNames = setToSortedString(componentWillUpdateUniqueNames);
    
  273. 
    
  274.       console.warn(
    
  275.         'componentWillUpdate has been renamed, and is not recommended for use. ' +
    
  276.           'See https://reactjs.org/link/unsafe-component-lifecycles for details.\n\n' +
    
  277.           '* Move data fetching code or side effects to componentDidUpdate.\n' +
    
  278.           '* Rename componentWillUpdate to UNSAFE_componentWillUpdate to suppress ' +
    
  279.           'this warning in non-strict mode. In React 18.x, only the UNSAFE_ name will work. ' +
    
  280.           'To rename all deprecated lifecycles to their new names, you can run ' +
    
  281.           '`npx react-codemod rename-unsafe-lifecycles` in your project source folder.\n' +
    
  282.           '\nPlease update the following components: %s',
    
  283.         sortedNames,
    
  284.       );
    
  285.     }
    
  286.   };
    
  287. 
    
  288.   let pendingLegacyContextWarning: FiberToFiberComponentsMap = new Map();
    
  289. 
    
  290.   // Tracks components we have already warned about.
    
  291.   const didWarnAboutLegacyContext = new Set<mixed>();
    
  292. 
    
  293.   ReactStrictModeWarnings.recordLegacyContextWarning = (
    
  294.     fiber: Fiber,
    
  295.     instance: any,
    
  296.   ) => {
    
  297.     const strictRoot = findStrictRoot(fiber);
    
  298.     if (strictRoot === null) {
    
  299.       console.error(
    
  300.         'Expected to find a StrictMode component in a strict mode tree. ' +
    
  301.           'This error is likely caused by a bug in React. Please file an issue.',
    
  302.       );
    
  303.       return;
    
  304.     }
    
  305. 
    
  306.     // Dedup strategy: Warn once per component.
    
  307.     if (didWarnAboutLegacyContext.has(fiber.type)) {
    
  308.       return;
    
  309.     }
    
  310. 
    
  311.     let warningsForRoot = pendingLegacyContextWarning.get(strictRoot);
    
  312. 
    
  313.     if (
    
  314.       fiber.type.contextTypes != null ||
    
  315.       fiber.type.childContextTypes != null ||
    
  316.       (instance !== null && typeof instance.getChildContext === 'function')
    
  317.     ) {
    
  318.       if (warningsForRoot === undefined) {
    
  319.         warningsForRoot = [];
    
  320.         pendingLegacyContextWarning.set(strictRoot, warningsForRoot);
    
  321.       }
    
  322.       warningsForRoot.push(fiber);
    
  323.     }
    
  324.   };
    
  325. 
    
  326.   ReactStrictModeWarnings.flushLegacyContextWarning = () => {
    
  327.     ((pendingLegacyContextWarning: any): FiberToFiberComponentsMap).forEach(
    
  328.       (fiberArray: FiberArray, strictRoot) => {
    
  329.         if (fiberArray.length === 0) {
    
  330.           return;
    
  331.         }
    
  332.         const firstFiber = fiberArray[0];
    
  333. 
    
  334.         const uniqueNames = new Set<string>();
    
  335.         fiberArray.forEach(fiber => {
    
  336.           uniqueNames.add(getComponentNameFromFiber(fiber) || 'Component');
    
  337.           didWarnAboutLegacyContext.add(fiber.type);
    
  338.         });
    
  339. 
    
  340.         const sortedNames = setToSortedString(uniqueNames);
    
  341. 
    
  342.         try {
    
  343.           setCurrentDebugFiberInDEV(firstFiber);
    
  344.           console.error(
    
  345.             'Legacy context API has been detected within a strict-mode tree.' +
    
  346.               '\n\nThe old API will be supported in all 16.x releases, but applications ' +
    
  347.               'using it should migrate to the new version.' +
    
  348.               '\n\nPlease update the following components: %s' +
    
  349.               '\n\nLearn more about this warning here: https://reactjs.org/link/legacy-context',
    
  350.             sortedNames,
    
  351.           );
    
  352.         } finally {
    
  353.           resetCurrentDebugFiberInDEV();
    
  354.         }
    
  355.       },
    
  356.     );
    
  357.   };
    
  358. 
    
  359.   ReactStrictModeWarnings.discardPendingWarnings = () => {
    
  360.     pendingComponentWillMountWarnings = [];
    
  361.     pendingUNSAFE_ComponentWillMountWarnings = [];
    
  362.     pendingComponentWillReceivePropsWarnings = [];
    
  363.     pendingUNSAFE_ComponentWillReceivePropsWarnings = [];
    
  364.     pendingComponentWillUpdateWarnings = [];
    
  365.     pendingUNSAFE_ComponentWillUpdateWarnings = [];
    
  366.     pendingLegacyContextWarning = new Map();
    
  367.   };
    
  368. }
    
  369. 
    
  370. export default ReactStrictModeWarnings;