Repository: facebook/react
File: packages/eslint-plugin-react-hooks/src/rules/RulesOfHooks.ts (TypeScript)

Code before:
            reactHooksMap.set(codePathSegment, reactHooks);
          }
          reactHooks.push(node.callee);
        }

        // useEffectEvent: useEffectEvent functions can be passed by reference within useEffect as well as in
        // another useEffectEvent
        if (
          node.callee.type === 'Identifier' &&
          (node.callee.name === 'useEffect' ||
            isUseEffectEventIdentifier(node.callee)) &&
          node.arguments.length > 0
        ) {
          // Denote that we have traversed into a useEffect call, and stash the CallExpr for
          // comparison later when we exit
          lastEffect = node;
        }
      },

      Identifier(node) {
        // This identifier resolves to a useEffectEvent function, but isn't being referenced in an
        // effect or another event function. It isn't being called either.
        if (
          lastEffect == null &&
          useEffectEventFunctions.has(node) &&
          node.parent.type !== 'CallExpression'
        ) {
          context.report({
            node,
            message:
              `\`${getSourceCode().getText(
                node,
              )}\` is a function created with React Hook "useEffectEvent", and can only be called from ` +
              'the same component. They cannot be assigned to variables or passed down.',
          });
        }
      },

      'CallExpression:exit'(node) {
        if (node === lastEffect) {
          lastEffect = null;
        }
      },

      FunctionDeclaration(node) {
        // function MyComponent() { const onClick = useEffectEvent(...) }
        if (isInsideComponentOrHook(node)) {
          recordAllUseEffectEventFunctions(getScope(node));
        }
      },


Review comment (suggestion):
The meaningful change here is that we error regardless of if the parent node is a call expression when we are not in an effect and the identifier is a uEE function. We tweak the error message based on whetehr it was called or not

Code after:
        if (isHook(node.callee)) {
          // Add the hook node to a map keyed by the code path segment. We will
          // do full code path analysis at the end of our code path.
          const reactHooksMap = last(codePathReactHooksMapStack);
          const codePathSegment = last(codePathSegmentStack);
          let reactHooks = reactHooksMap.get(codePathSegment);
          if (!reactHooks) {
            reactHooks = [];
            reactHooksMap.set(codePathSegment, reactHooks);
          }
          reactHooks.push(node.callee);
        }

        // useEffectEvent: useEffectEvent functions can be passed by reference within useEffect as well as in
        // another useEffectEvent
        if (
          node.callee.type === 'Identifier' &&
          (node.callee.name === 'useEffect' ||
            isUseEffectEventIdentifier(node.callee)) &&
          node.arguments.length > 0
        ) {
          // Denote that we have traversed into a useEffect call, and stash the CallExpr for
          // comparison later when we exit
          lastEffect = node;
        }
      },

      Identifier(node) {
        // This identifier resolves to a useEffectEvent function, but isn't being referenced in an
        // effect or another event function. It isn't being called either.
        if (lastEffect == null && useEffectEventFunctions.has(node)) {
          const message =
            `\`${getSourceCode().getText(
              node,
            )}\` is a function created with React Hook "useEffectEvent", and can only be called from ` +
            'the same component.' +
            (node.parent.type === 'CallExpression'
              ? ''
              : ' They cannot be assigned to variables or passed down.');
          context.report({
            node,
            message,
          });
        }
      },

      'CallExpression:exit'(node) {
        if (node === lastEffect) {
          lastEffect = null;
        }
      },