在 React 功能组件中出现此错误 "Invalid hook call. Hooks can only be called inside of the body of a function component."?

Getting this error "Invalid hook call. Hooks can only be called inside of the body of a function component." inside a react functional component?

我收到此错误“挂钩调用无效。挂钩只能在函数组件的主体内部调用。”当我尝试 运行 我的功能时。我正在尝试 运行 生成 reCaptcha 令牌的脚本,脚本如下:

This component should generate the token(this is where I get the error)

import * as React from 'react'
import { RECAPTCHA_KEY } from '../../../utils/env'

// @ts-ignore
declare const window: any

interface RecaptchaProps {
  actionType: string
}
export const RecaptchaGen = ({ actionType }: RecaptchaProps) => {
  const siteKey = RECAPTCHA_KEY
  const [loaded, setLoaded] = React.useState(false)
  React.useEffect(() => {
    const scriptTag = document.createElement('script')
    scriptTag.src = 'https://www.google.com/recaptcha/api.js?render=' + siteKey
    document.appendChild(scriptTag)

    return () => {
      scriptTag.remove()
      setLoaded(false)
    }
  }, [siteKey])

  React.useEffect(() => {
    if (!loaded) return
    window.grecaptcha.ready(function () {
      window.grecaptcha
        .execute(siteKey, {
          action: actionType,
        })
        .then(function (token: string) {
          //reCaptch token generated needs to be sent to the back end for validation
          console.log(token)
        })
    })
  }, [loaded, actionType, siteKey])
}

Here within another component, I call the prior script component with an action type passed through but I get the react hook error mentioned(only showing relevant code snipets).

import * as React from 'react'
import { RecaptchaGen } from '../../../components/_molecules/Recaptcha'

const onLoginClick = () => {
    RecaptchaGen({ actionType: 'login' })
  }

我认为问题出在我 calling/using 导入组件的方式上,但我找不到解决方案?

您正在常规 js 函数中使用 useEffect 钩子。

hooks 只能在有效的 React 组件中调用。 RepcaptchaGen 不是反应组件,因为它不使用反应组件特定的东西,比如返回一些 jsx.

名称 RecaptchaGen 表明它是构造函数或组件,但两者都不是。它是一个自定义挂钩,因此应以 use 开头,例如:useRecaptchaGen.

以下是如何在您的组件中使用它:

export const useRecaptchaGen = (action) => {
  if (!action) {
    return;
  }
  const { actionType }: RecaptchaProps = action;
  //....rest of your code
};

const Component = () => {
  const [action, setAction] = React.useState(false);
  const onLoginClick = () => {
    setAction({ actionType: 'login' });
  };
  //cannot conditionally call hooks
  useRecaptchaGen(action);
};

这是因为您没有 return在 RecaptchaGen 函数中输入任何代码。 JSX return 是 React Functional 组件与常规 javascript 函数的区别所在,而常规 javascript 函数不能使用钩子。如果要解决此问题,请添加 return 语句。

我不熟悉你的具体用例,但一个常见的模式是将一些效果逻辑封装到一个由你的自定义钩子返回的函数中,然后任何普通的 JS 函数(回调或不回调)都可以调用那个函数。

  1. RecaptchaGen 重命名为 useRecaptchaGen 以便它可以用作 React 挂钩。

  2. Return 一个基本取代第二个 useEffect 回调的函数。

    export const useRecaptchaGen = ({ actionType }: RecaptchaProps) => {
      const siteKey = RECAPTCHA_KEY
      const [loaded, setLoaded] = React.useState(false)
      React.useEffect(() => {
        const scriptTag = document.createElement('script')
        scriptTag.src = 'https://www.google.com/recaptcha/api.js?render=' + siteKey
        document.appendChild(scriptTag)
    
        return () => {
          scriptTag.remove()
          setLoaded(false)
        }
      }, [siteKey]);
    
      const generateRecaptcha = () => {
        if (!loaded) return;
        window.grecaptcha.ready(function () {
          window.grecaptcha
            .execute(siteKey, {
              action: actionType,
            })
            .then(function (token: string) {
              //reCaptch token generated needs to be sent to the back end for validation
              console.log(token)
            })
        })
      };
    
      return { generateRecaptcha };
    }
    
  3. 在组件中使用新的钩子和解构generateRecaptcha

    const { generateRecaptcha } = useRecaptchaGen({ actionType: 'login' });
    
  4. onLoginClick 处理程序中调用 generateRecaptcha

    const onLoginClick = () => {
      generateRecaptcha();
    }