Javascript React Hooks 错误:只能在函数组件内部调用 Hooks

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/53028117/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 05:03:20  来源:igfitidea点击:

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

javascriptreactjsreact-hooks

提问by loganfromlogan

I am getting this error when using the useStatehook. I have this in it's basic form, looking at the react docsfor a reference, but am still getting this error. I'm ready for the face palm moment...

使用useState钩子时出现此错误。我有它的基本形式,查看反应文档以供参考,但仍然收到此错误。我已经准备好迎接面掌时刻了...

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

采纳答案by Ninh Pham

Updated: 2018-Dec

更新时间:2018-12 月

New version of react-hot-loaderis out now, link. Hooks is now working out of the box. Thank to the author, theKashey.

新版本react-hot-loader现已发布,链接。Hooks 现在可以开箱即用了。感谢作者,theKashey。

Check out this boilerplate https://github.com/ReeganExE/react-hooks-boilerplate

看看这个样板https://github.com/ReeganExE/react-hooks-boilerplate

  • React Hooks
  • React Hot Loader
  • Webpack, Babel, ESLint Airbnb
  • 反应钩子
  • 反应热加载器
  • Webpack、Babel、ESLint Airbnb

Previous Answer:

上一个答案:

First, make sure you installed react@nextand react-dom@next.

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

Then check for you are using react-hot-loaderor not.

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

In my case, disable hot loader & HMR could get it work.

在我的情况下,禁用热加载器和 HMR 可以让它工作。

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

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

Quoted:

引:

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.

是的。RHL 与钩子 100% 不兼容。这背后有几个原因:

SFC 正在转换为 Class 组件。有理由 - 能够在 HMR 上强制更新,只要 SFC 上没有“更新”方法。我正在寻找强制更新的其他方式(就像这样。所以 RHL 正在杀死 SFC。

“热替换渲染”。RHL 正在尝试做 React 的工作,渲染新旧应用程序,合并它们。所以,显然,现在已经坏了。

我将起草一份 PR,以缓解这两个问题。它会起作用,但不是今天。

There is a more proper fix, which would work - cold API

有一个更合适的修复方法,它可以工作 -冷 API

You may disable RHL for any custom type.

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

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

cold(MyComponent);

Search for "useState/useEffect"inside component source code, and "cold" it.

搜索"useState/useEffect"内部组件源代码,并“冷”它。

Updated:

更新:

As per updatedfrom react-hot-loader maintainer, you could try react-hot-loader@nextand set the config as bellow:

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

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

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

Thank to @loganfromlogan for the update.

感谢@loganfromlogan 的更新。

回答by JLarky

My problem was forgetting to update react-dommodule. See issue.

我的问题是忘记更新react-dom模块。见问题

回答by peternyc

Had the same issue. My problem was related to React Router. I had accidentally used

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

<Route render={ComponentUsingHooks} />

instead of

代替

<Route component={ComponentUsingHooks} />

回答by erica mitchell

I experienced this error while using Parcel's Hot Module Replacement, and fixed by updating react-domto it's alpha version:

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

yarn add [email protected]

See this issue.

看到这个问题。

回答by rista404

I had a problem in a monorepo, where a package doczused [email protected]and the final output bundle had two react versions.

我在一个monorepo,其中包有一个问题docz使用[email protected]以及最终输出束有两个反应的版本。

Issue on Github

Github 上的问题

Fixed it by removing the package

通过删除包修复它

回答by mickmister

I was able to solve this by importing React's primitive hooks in the component file, then passing them into my custom hooks. For some reason, the error only occurs when I import the React hook (like useState) in my custom hook file.

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

I'm importing useState in my component file:

我在我的组件文件中导入 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});
    ...
}

Then in my hook file:

然后在我的钩子文件中:

// 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];
}

This method has improved the testability of my hooks because I don't need to mock React's library to provide the primitive hooks. Instead, we can pass in a mock useStatehook right into the custom hook's function. I think this improves code quality, as your custom hooks now have no coupling with the React library, allowing for more natural functional programming and testing.

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

回答by protoEvangelion

The problem for me was indeed react-hot-loader.

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

You can disable react-hot-loader for a single componentinstead of the entire app using the coldmethod like this:

您可以使用如下方法为单个组件而不是整个应用程序禁用 react-hot-loadercold

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

export const YourComponent = cold(() => {

  // ... hook code

  return (
    // ...
  )
})

OR

或者

export default cold(YourComponent)

回答by Marcelo Cardoso

For those who come across this issue when using MobX and wrapping a component with an observer, make sure you use mobx-react-liteinstead of mobx-react.

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

MAY 29 UPDATE

5 月 29 日更新

From mobx-react6.0.0onward, hook based components are now supported by mobx-react, thus, there is no need for mobx-react-liteusage anymore (if that was your problem).

从那时mobx-react6.0.0起,mobx-react 支持基于钩子的组件,因此不再需要mobx-react-lite使用(如果那是您的问题)。

回答by SkipHyman

Just to elaborate on @rista404's answer, including duplicate versionsof react(and perhaps react-dom) will yield the same error depending on where you are using your hooks. Here are two examples...

只是为了阐述@ rista404的答案,包括重复版本react(也许react-dom)将取决于你使用的是挂钩产生相同的错误。这里有两个例子...

  1. An external dependency includes another version of reactin its dependencies, likely by mistake as reactshould usually be a peer dependency. If npmdoesn't automatically dedupe this version with your local version, you may see this error. This is what @rista404 was referring to.
  2. You npm linka package that includes reactin its devDependenciesor dependencies. Now, for modules in this package, you may see errors if they pull a different version of reactfrom the their local node_modulesdirectory rather than the parent project's.
  1. 外部依赖包括另一个版本的reactin dependencies,可能是错误的,react通常应该是对等依赖。如果npm未使用本地版本自动删除此版本的重复数据,您可能会看到此错误。这就是@rista404 所指的。
  2. npm link是一个包含react在其devDependenciesdependencies. 现在,对于此包中的模块,如果它们react从其本地node_modules目录而不是父项目中提取不同版本的 ,您可能会看到错误。

The latter can be fixed when bundling with webpackby using resolve.aliaslike so...

后者可以webpack通过使用resolve.alias像这样捆绑时固定......

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

This will ensure reactis always pulled from the parent project's node_modulesdirectory.

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

回答by Paul Razvan Berg

For fellow users of yarn workspaces, here's my situation and how I figured it out.

对于纱线工作区的其他用户,这是我的情况以及我是如何解决的。

  • 包裹
      • 反应@16.8.6
    • 酒吧
      • 反应@16.10.1

The Facebook docs on Invalid Hook Call Warningsay nothing about yarn workspaces, so I assumed my config was correct. But it wasn't. You can fix the error only by using the same version across all your packages.

Invalid Hook Call Warning上的 Facebook 文档没有提到纱线工作区,所以我认为我的配置是正确的。但事实并非如此。您只能通过在所有包中使用相同的版本来修复错误。

In the example above, you have to bump the version of react from "foo" to 16.10.1, so that it matches the react version from "bar".

在上面的示例中,您必须将 react 版本从“foo”提升到 16.10.1,以便它与“bar”中的 react 版本匹配。

Bonus: see this discussion on GitHubfor a beautiful collection of emotional baggage offloaded on the Internet.

奖励:请参阅 GitHub 上的此讨论,了解在 Internet 上卸下的一组精美的情感包袱。