【问题标题】:React 17.0.1: Invalid hook call. Hooks can only be called inside of the body of a function componentReact 17.0.1:无效的钩子调用。 Hooks 只能在函数组件的主体内部调用
【发布时间】:2021-05-05 00:53:19
【问题描述】:

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

当我使用以下代码时,我得到一个错误:

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 中使用react 17.0.1 和react-dom 17.0.1。
  2. 我已经安装了eslint-plugin-react-hooks 规则来识别我是否在我的功能组件中没有正确使用钩子。
  3. 我已使用 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

【问题讨论】:

标签: reactjs npm eslint react-dom


【解决方案1】:

你调用这个 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);
          //    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

【讨论】:

  • 成功了!是否有等效的 javascript 来执行此操作?
  • 可以,但我不推荐:ReactDOM.render(React.createElement(LoginForm, { onToken }), domContainer)
  • 啊,所以无论如何您仍然需要在该解决方案中导入 React。非常感谢您的帮助!
  • 我猜 react 17 在你只需要 jsx 的时候消除了导入 React 本身
  • @AmirhosseinEbrahimi 是的,这很酷:reactjs.org/blog/2020/09/22/… 虽然通过 React 创建元素比完全删除它更混淆
【解决方案2】:

我在我的仓库中遇到了类似的错误。当我开始将反应从 16 提高到 17 时,它开始出现。 后来我意识到它是由于 react16 被不同的依赖项拉入 node_modules 并删除它修复了我的问题

【讨论】:

    猜你喜欢
    • 2020-06-22
    • 2019-09-07
    • 1970-01-01
    • 2021-02-08
    • 2021-03-30
    • 2020-11-20
    • 2021-10-18
    • 1970-01-01
    • 2021-07-12
    相关资源
    最近更新 更多