React 17.0.1:无效的挂钩调用。钩子只能在函数组件的内部调用

React 17.0.1: Invalid hook call. Hooks can only be called inside of the body of a function component

这里是非常新的 React 用户。几个小时以来,我一直在解决这个错误。我以前让这个组件作为 class 工作,但最近似乎每个人都在向功能组件迁移,所以我正在尝试转换它。我在没有使用状态的情况下进行了中间转换并且工作正常,但是我在将用户名和密码转换为状态值时遇到了问题。

当我使用以下代码时,出现错误:

Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.

我已多次阅读链接的故障排除页面,并尝试修复所有三个可能的原因,但均未成功。

  1. 我在 devDependencies.
  2. 中使用 react 17.0.1 和 react-dom 17.0.1
  3. 我已经安装了 eslint-plugin-react-hooks 规则来识别我是否没有在我的功能组件中正确使用挂钩。
  4. 我已经使用 npm ls reactnpm ls react-dom 来确认我没有重复的 React 版本。

LoginForm.jsx

import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
const $ = require('jquery');

const LoginForm = ({ onToken }) => {

    const [username, setUsername] = useState('');
    const [password, setPassword] = useState('');

    const submit = (event) => {
        // DO NOT POST PARAMS
        event.preventDefault();
        // AJAX username and password
        const loginData = {
            username: username,
            password: password
        };
        const options = {
            url: 'api/login',
            type: 'POST',
            contentType: 'application/json; charset=utf-8',
            dataType: 'json',
            data: JSON.stringify(loginData),
            success: (data) => {
                console.log(data);
                onToken(data.token);
            }
        };

        $.ajax(options);

        console.log('Submitted!');
    };

    return (
        <form onSubmit={submit}>
            <label htmlFor="username">Username:</label><br/>
            <input value={username} onChange={e => setUsername(e.target.value)} type="text" id="username" name="username"/><br/>
            <label htmlFor="password">Password:</label><br/>
            <input value={password} onChange={e => setPassword(e.target.value)} type="password" id="password" name="password"/><br/>
            <input type="submit" value="Login"/>
        </form>
    );
};

LoginForm.propTypes = {
    onToken: PropTypes.func
};

export default LoginForm;

我已经在我的项目存储库中创建了一个分支,因此您可以查看任何其他信息:

分支机构:https://github.com/GibsDev/node-password-manager/tree/login-conversion

提交:https://github.com/GibsDev/node-password-manager/commit/e0714b16bdbbf339fabf1aa4f6eefacd6d053427

你称这个 loginForm 就好像它是一个 普通函数 ,而不是一个 React 组件:

const loginForm = LoginForm({
    onToken: token => {
        const url = new URL(window.location.href);
        const returnurl = url.searchParams.get('returnurl');
        if (returnurl) {
            window.location.href = decodeURIComponent(returnurl);
        } else {
            window.location.href = '/';
        }
    }
});

ReactDOM.render(loginForm, domContainer);

因此,它没有被包裹在React.createElement中,所以它认为钩子调用是无效的。

改为使用 JSX 语法:

const onToken = token => {
        const url = new URL(window.location.href);
        const returnurl = url.searchParams.get('returnurl');
        if (returnurl) {
            window.location.href = decodeURIComponent(returnurl);
        } else {
            window.location.href = '/';
        }
}

ReactDOM.render(<LoginForm onToken={onToken} />, domContainer);
          //    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

我的回购中出现了类似的错误。当我开始从 16 反应到 17 时,它开始出现。 后来我意识到它是由于 react16 被不同的依赖项拉入 node_modules 并删除它解决了我的问题