Repository: facebook/react
Pull request: [lint] Remove experimental gating useEffectEvent rules

Stacked on https://github.com/facebook/react/pull/34637

`useEffectEvent` is now in canary so we need to remove this `__EXPERIMENTAL__` gating on the rules and tests

Changed files:
filename: packages/eslint-plugin-react-hooks/__tests__/ESLintRuleExhaustiveDeps-test.js
patch: @@ -1549,6 +1549,21 @@ const tests = {
         },
       },
     },
+    {
+      code: normalizeIndent`
+        function MyComponent({ theme }) {
+          const onStuff = useEffectEvent(() => {
+            showNotification(theme);
+          });
+          useEffect(() => {
+            onStuff();
+          }, []);
+          React.useEffect(() => {
+            onStuff();
+          }, []);
+        }
+      `,
+    },
   ],
   invalid: [
     {
@@ -7819,31 +7834,6 @@ const tests = {
         },
       ],
     },
-  ],
-};
-
-if (__EXPERIMENTAL__) {
-  tests.valid = [
-    ...tests.valid,
-    {
-      code: normalizeIndent`
-        function MyComponent({ theme }) {
-          const onStuff = useEffectEvent(() => {
-            showNotification(theme);
-          });
-          useEffect(() => {
-            onStuff();
-          }, []);
-          React.useEffect(() => {
-            onStuff();
-          }, []);
-        }
-      `,
-    },
-  ];
-
-  tests.invalid = [
-    ...tests.invalid,
     {
       code: normalizeIndent`
         function MyComponent({ theme }) {
@@ -7907,8 +7897,8 @@ if (__EXPERIMENTAL__) {
         },
       ],
     },
-  ];
-}
+  ],
+};
 
 // Tests that are only valid/invalid across parsers supporting Flow
 const testsFlow = {

filename: packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js
patch: @@ -602,6 +602,143 @@ const allTests = {
         },
       },
     },
+    {
+      code: normalizeIndent`
+        // Valid because functions created with useEffectEvent can be called in a useEffect.
+        function MyComponent({ theme }) {
+          const onClick = useEffectEvent(() => {
+            showNotification(theme);
+          });
+          useEffect(() => {
+            onClick();
+          });
+          React.useEffect(() => {
+            onClick();
+          });
+        }
+      `,
+    },
+    {
+      code: normalizeIndent`
+        // Valid because functions created with useEffectEvent can be passed by reference in useEffect
+        // and useEffectEvent.
+        function MyComponent({ theme }) {
+          const onClick = useEffectEvent(() => {
+            showNotification(theme);
+          });
+          const onClick2 = useEffectEvent(() => {
+            debounce(onClick);
+            debounce(() => onClick());
+            debounce(() => { onClick() });
+            deboucne(() => debounce(onClick));
+          });
+          useEffect(() => {
+            let id = setInterval(() => onClick(), 100);
+            return () => clearInterval(onClick);
+          }, []);
+          React.useEffect(() => {
+            let id = setInterval(() => onClick(), 100);
+            return () => clearInterval(onClick);
+          }, []);
+          return null;
+        }
+      `,
+    },
+    {
+      code: normalizeIndent`
+        function MyComponent({ theme }) {
+          useEffect(() => {
+            onClick();
+          });
+          const onClick = useEffectEvent(() => {
+            showNotification(theme);
+          });
+        }
+      `,
+    },
+    {
+      code: normalizeIndent`
+        function MyComponent({ theme }) {
+          // Can receive arguments
+          const onEvent = useEffectEvent((text) => {
+            console.log(text);
+          });
+
+          useEffect(() => {
+            onEvent('Hello world');
+          });
+          React.useEffect(() => {
+            onEvent('Hello world');
+          });
+        }
+      `,
+    },
+    {
+      code: normalizeIndent`
+        // Valid because functions created with useEffectEvent can be called in useLayoutEffect.
+        function MyComponent({ theme }) {
+          const onClick = useEffectEvent(() => {
+            showNotification(theme);
+          });
+          useLayoutEffect(() => {
+            onClick();
+          });
+          React.useLayoutEffect(() => {
+            onClick();
+          });
+        }
+      `,
+    },
+    {
+      code: normalizeIndent`
+        // Valid because functions created with useEffectEvent can be called in useInsertionEffect.
+        function MyComponent({ theme }) {
+          const onClick = useEffectEvent(() => {
+            showNotification(theme);
+          });
+          useInsertionEffect(() => {
+            onClick();
+          });
+          React.useInsertionEffect(() => {
+            onClick();
+          });
+        }
+      `,
+    },
+    {
+      code: normalizeIndent`
+        // Valid because functions created with useEffectEvent can be passed by reference in useLayoutEffect 
+        // and useInsertionEffect.
+        function MyComponent({ theme }) {
+          const onClick = useEffectEvent(() => {
+            showNotification(theme);
+          });
+          const onClick2 = useEffectEvent(() => {
+            debounce(onClick);
+            debounce(() => onClick());
+            debounce(() => { onClick() });
+            deboucne(() => debounce(onClick));
+          });
+          useLayoutEffect(() => {
+            let id = setInterval(() => onClick(), 100);
+            return () => clearInterval(onClick);
+          }, []);
+          React.useLayoutEffect(() => {
+            let id = setInterval(() => onClick(), 100);
+            return () => clearInterval(onClick);
+          }, []);
+          useInsertionEffect(() => {
+            let id = setInterval(() => onClick(), 100);
+            return () => clearInterval(onClick);
+          }, []);
+          React.useInsertionEffect(() => {
+            let id = setInterval(() => onClick(), 100);
+            return () => clearInterval(onClick);
+          }, []);
+          return null;
+        }
+      `,
+    },
   ],
   invalid: [
     {
@@ -1407,152 +1544,6 @@ const allTests = {
       },
       errors: [useEffectEventError('onClick', true)],
     },
-  ],
-};
-
-if (__EXPERIMENTAL__) {
-  allTests.valid = [
-    ...allTests.valid,
-    {
-      code: normalizeIndent`
-        // Valid because functions created with useEffectEvent can be called in a useEffect.
-        function MyComponent({ theme }) {
-          const onClick = useEffectEvent(() => {
-            showNotification(theme);
-          });
-          useEffect(() => {
-            onClick();
-          });
-          React.useEffect(() => {
-            onClick();
-          });
-        }
-      `,
-    },
-    {
-      code: normalizeIndent`
-        // Valid because functions created with useEffectEvent can be passed by reference in useEffect
-        // and useEffectEvent.
-        function MyComponent({ theme }) {
-          const onClick = useEffectEvent(() => {
-            showNotification(theme);
-          });
-          const onClick2 = useEffectEvent(() => {
-            debounce(onClick);
-            debounce(() => onClick());
-            debounce(() => { onClick() });
-            deboucne(() => debounce(onClick));
-          });
-          useEffect(() => {
-            let id = setInterval(() => onClick(), 100);
-            return () => clearInterval(onClick);
-          }, []);
-          React.useEffect(() => {
-            let id = setInterval(() => onClick(), 100);
-            return () => clearInterval(onClick);
-          }, []);
-          return null;
-        }
-      `,
-    },
-    {
-      code: normalizeIndent`
-        function MyComponent({ theme }) {
-          useEffect(() => {
-            onClick();
-          });
-          const onClick = useEffectEvent(() => {
-            showNotification(theme);
-          });
-        }
-      `,
-    },
-    {
-      code: normalizeIndent`
-        function MyComponent({ theme }) {
-          // Can receive arguments
-          const onEvent = useEffectEvent((text) => {
-            console.log(text);
-          });
-
-          useEffect(() => {
-            onEvent('Hello world');
-          });
-          React.useEffect(() => {
-            onEvent('Hello world');
-          });
-        }
-      `,
-    },
-    {
-      code: normalizeIndent`
-        // Valid because functions created with useEffectEvent can be called in useLayoutEffect.
-        function MyComponent({ theme }) {
-          const onClick = useEffectEvent(() => {
-            showNotification(theme);
-          });
-          useLayoutEffect(() => {
-            onClick();
-          });
-          React.useLayoutEffect(() => {
-            onClick();
-          });
-        }
-      `,
-    },
-    {
-      code: normalizeIndent`
-        // Valid because functions created with useEffectEvent can be called in useInsertionEffect.
-        function MyComponent({ theme }) {
-          const onClick = useEffectEvent(() => {
-            showNotification(theme);
-          });
-          useInsertionEffect(() => {
-            onClick();
-          });
-          React.useInsertionEffect(() => {
-            onClick();
-          });
-        }
-      `,
-    },
-    {
-      code: normalizeIndent`
-        // Valid because functions created with useEffectEvent can be passed by reference in useLayoutEffect 
-        // and useInsertionEffect.
-        function MyComponent({ theme }) {
-          const onClick = useEffectEvent(() => {
-            showNotification(theme);
-          });
-          const onClick2 = useEffectEvent(() => {
-            debounce(onClick);
-            debounce(() => onClick());
-            debounce(() => { onClick() });
-            deboucne(() => debounce(onClick));
-          });
-          useLayoutEffect(() => {
-            let id = setInterval(() => onClick(), 100);
-            return () => clearInterval(onClick);
-          }, []);
-          React.useLayoutEffect(() => {
-            let id = setInterval(() => onClick(), 100);
-            return () => clearInterval(onClick);
-          }, []);
-          useInsertionEffect(() => {
-            let id = setInterval(() => onClick(), 100);
-            return () => clearInterval(onClick);
-          }, []);
-          React.useInsertionEffect(() => {
-            let id = setInterval(() => onClick(), 100);
-            return () => clearInterval(onClick);
-          }, []);
-          return null;
-        }
-      `,
-    },
-  ];
-  allTests.invalid = [
-    ...allTests.invalid,
     {
       code: normalizeIndent`
         function MyComponent({ theme }) {
@@ -1659,8 +1650,8 @@ if (__EXPERIMENTAL__) {
         useEffectEventError('onClick', true),
       ],
     },
-  ];
-}
+  ],
+};
 
 function conditionalError(hook, hasPreviousFinalizer = false) {
   return {

filename: packages/eslint-plugin-react-hooks/src/rules/ExhaustiveDeps.ts
patch: @@ -2122,10 +2122,7 @@ function isAncestorNodeOf(a: Node, b: Node): boolean {
 }
 
 function isUseEffectEventIdentifier(node: Node): boolean {
-  if (__EXPERIMENTAL__) {
-    return node.type === 'Identifier' && node.name === 'useEffectEvent';
-  }
-  return false;
+  return node.type === 'Identifier' && node.name === 'useEffectEvent';
 }
 
 function getUnknownDependenciesMessage(reactiveHookName: string): string {

filename: packages/eslint-plugin-react-hooks/src/rules/RulesOfHooks.ts
patch: @@ -20,7 +20,7 @@ import type {
 
 // @ts-expect-error untyped module
 import CodePathAnalyzer from '../code-path-analysis/code-path-analyzer';
-import { getAdditionalEffectHooksFromSettings } from '../shared/Utils';
+import {getAdditionalEffectHooksFromSettings} from '../shared/Utils';
 
 /**
  * Catch all identifiers that begin with "use" followed by an uppercase Latin
@@ -167,10 +167,7 @@ function isEffectIdentifier(node: Node, additionalHooks?: RegExp): boolean {
   return false;
 }
 function isUseEffectEventIdentifier(node: Node): boolean {
-  if (__EXPERIMENTAL__) {
-    return node.type === 'Identifier' && node.name === 'useEffectEvent';
-  }
-  return false;
+  return node.type === 'Identifier' && node.name === 'useEffectEvent';
 }
 
 function isUseIdentifier(node: Node): boolean {
@@ -200,7 +197,8 @@ const rule = {
   create(context: Rule.RuleContext) {
     const settings = context.settings || {};
 
-    const additionalEffectHooks = getAdditionalEffectHooksFromSettings(settings);
+    const additionalEffectHooks =
+      getAdditionalEffectHooksFromSettings(settings);
 
     let lastEffect: CallExpression | null = null;
     const codePathReactHooksMapStack: Array<