React Hooks Error: Hooks can only be called inside the body of a function component

React Hooks Error: Hooks can only be called inside the body of a function component

我在使用 useState 挂钩时遇到此错误。我有它的基本形式,查看 react docs 作为参考,但我仍然收到此错误。我已经准备好迎接掌心时刻了...

export function Header() {
  const [count, setCount] = useState(0)
  return <span>header</span>
}

更新时间:2018 年 12 月

react-hot-loader 的新版本现已发布,link。 Hooks 现在开箱即用。感谢作者 theKashey.

查看此样板文件 https://github.com/ReeganExE/react-hooks-boilerplate

  • 反应挂钩
  • React 热加载程序
  • Webpack、Babel、ESLint Airbnb

上一个答案:

首先,确保安装了 react@nextreact-dom@next

然后检查你是否在使用react-hot-loader

在我的例子中,禁用热加载器和 HMR 可以让它工作。

https://github.com/gaearon/react-hot-loader/issues/1088

引用:

Yes. RHL is 100% not compatible with hooks. There is just a few reasons behind it:

SFC are being converted to Class components. There is reason - to be able to forceUpdate on HMR, as long there is no "update" method on SFC. I am looking for other way of forcing the update (like this. So RHL is killing SFC.

"hotReplacementRender". RHL is trying to do React's job, and render the old and the new app, to merge them. So, obviously, that's broken now.

I am going to draft a PR, to mitigate both problems. It will work, but not today.

有一个更合适的修复方法,它会起作用 - cold API

您可以为任何自定义类型禁用 RHL。

import { cold } from 'react-hot-loader';

cold(MyComponent);

在组件源代码中搜索"useState/useEffect",然后"cold"它。

已更新:

根据 react-hot-loader 维护者的 updated,您可以尝试 react-hot-loader@next 并将配置设置如下:

import { setConfig } from 'react-hot-loader';

setConfig({
  // set this flag to support SFC if patch is not landed
  pureSFC: true
});

感谢@loganfromlogan 的更新。

我的问题确实是react-hot-loader

您可以 禁用单个组件的 react-hot-loader 而不是使用 cold 方法的整个应用程序,如下所示:

import { cold } from 'react-hot-loader'

export const YourComponent = cold(() => {

  // ... hook code

  return (
    // ...
  )
})

export default cold(YourComponent)

我能够通过在组件文件中导入 React 的原始挂钩,然后将它们传递到我的自定义挂钩中来解决这个问题。出于某种原因,只有当我在我的自定义挂钩文件中导入 React 挂钩(如 useState)时才会出现错误。

我正在我的组件文件中导入 useState:

import React, {useState} from 'react'; // import useState

import {useCustomHook} from '../hooks/custom-hook'; // import custom hook

const initialState = {items: []};
export default function MyComponent(props) {
    const [state, actions] = useCustomHook(initialState, {useState});
    ...
}

然后在我的钩子文件中:

// do not import useState here

export function useCustomHook(initialValue, {useState}) {
    const [state, setState] = useState(initialValue || {items: []});

    const actions = {
        add: (item) => setState(currentState => {
            const newItems = currentState.items.concat([item]);
            return {
                ...currentState,
                items: newItems,
            };
        }),
    };

    return [state, actions];
}

这种方法提高了我的钩子的可测试性,因为我不需要模拟 React 的库来提供原始钩子。相反,我们可以将模拟 useState 挂钩直接传递到自定义挂钩的函数中。我认为这提高了代码质量,因为您的自定义钩子现在与 React 库没有耦合,允许更自然的函数式编程和测试。

我的问题是忘记更新 react-dom 模块。 See issue.

我在使用 Parcel's Hot Module Replacement 时遇到了这个错误,并通过将 react-dom 更新到它的 alpha 版本来修复:

yarn add react-dom@16.7.0-alpha.0

See this issue.

找到 react-hot-loader 的解决方法,而修复它的 PR 是入站的。

将调用 hooks 的函数包装在 React.memo 中,防止在未更改的情况下进行热重载。

const MyFunc = React.memo(({props}) => {...

解决方案的功劳: https://github.com/gatsbyjs/gatsby/issues/9489

我在 monorepo 中遇到问题,其中包 docz 使用 react@16.6.3 并且最终输出包有两个反应版本。

Issue on Github

通过删除包修复了它

更新 package.json react-dom 版本为 react

如果您使用的是 Create React App,则还必须使用 React 和 React-dom 版本更新 "react-scripts" 版本。

 "react-scripts": "2.1.5",
 "react": "^16.8.1",
 "react-dom": "^16.8.1",

这个组合效果很好。

我的问题如下:

我在做: ReactDOM.render(Example(), app);

而我应该做的是: ReactDOM.render(<Example />, app);

有同样的问题。我的问题与 React Router 有关。我不小心用了

<Route render={ComponentUsingHooks} />

而不是

<Route component={ComponentUsingHooks} />

对于那些在使用 MobX 并用 observer 包装组件时遇到此问题的人,请确保使用 mobx-react-lite 而不是 mobx-react

5 月 29 日更新

mobx-react 6.0.0 开始,hook based components are now supported by mobx-react,因此,不再需要使用 mobx-react-lite(如果那是你的问题)。

只是为了详细说明@rista404 的回答,包括react(也许react-dom)的重复版本 会产生相同的错误,具体取决于您在哪里正在使用你的钩子。这里有两个例子...

  1. 外部依赖项在其 dependencies 中包含另一个版本的 react,这可能是错误的,因为 react 通常应该是对等依赖项。如果 npm 没有自动将此版本与您的本地版本进行重复数据删除,您可能会看到此错误。这就是@rista404 所指的。
  2. npm link 一个在其 devDependenciesdependencies 中包含 react 的包裹。现在,对于这个包中的模块,如果它们从本地 node_modules 目录而不是父项目的目录中提取不同版本的 react,您可能会看到错误。

后者可以在与 webpack 捆绑时通过使用 resolve.alias 来修复...

    resolve: {
        alias: {
            'react': path.resolve(__dirname, 'node_modules/react'),
            'react-dom': path.resolve(__dirname, 'node_modules/react-dom')
        }
    }

这将确保 react 始终从父项目的 node_modules 目录中提取。

对我来说,这是因为我有一个新版本的 React (16.8.6) 和一个旧版本的 react-dom (16.6.1)。

https://reactjs.org/warnings/invalid-hook-call-warning.html#mismatching-versions-of-react-and-react-dom

同时升级到@latest (16.8.6) 修复了错误。

对于 yarn workspaces 的其他用户,这是我的情况以及我是如何解决的。

      • react@16.8.6
      • react@16.10.1

Invalid Hook Call Warning 上的 Facebook 文档没有提及 yarn 工作区,所以我假设我的配置是正确的。但事实并非如此。您只能通过在 所有包.

中使用相同版本来修复错误

在上面的示例中,您必须将 react 的版本从 "foo" 提高到 16.10.1,以便它与 "bar".

的 react 版本相匹配

奖励:see this discussion on GitHub 收集了在 Internet 上卸载的精美情感包袱。

另一个解决方案,如果你 运行 使用 npm link:

您可以 npm link 在您的库中做出反应,如下所述: https://reactjs.org/warnings/invalid-hook-call-warning.html#duplicate-react

或者在你的库中将 react 设置为 peerDependency 然后使用 npm link --only=production

在我的案例中,我在 useEffect 中调用了 useSelector !!

2021 年 6 月答案

我在使用 react-electron-boilerplate 应用程序时遇到了这个问题。

由于这个不幸的错误,许多插件和库如Material-UI无法在我的项目中使用,经过大量搜索后,我可以解决问题:

我刚刚将 reactreact-dom 升级到最新版本。

这个命令完成了工作!

yarn add react@latest react-dom@latest

检查 reactreact-dom 版本 完全相等 。注意版本上的音调 ^ 符号。

"17.0.0" 不能与 "^17.0.0"

相同

npm - Carret 范围:https://github.com/npm/node-semver#caret-ranges-123-025-004 反应 - 更新日志:https://github.com/facebook/react/blob/main/CHANGELOG.md

这是使用 -E 或 --save-exact 更好地安装软件包的原因之一

npm install --save --save-exact <package@vesion>