React Hooks错误:只能在函数组件的主体内部调用Hook

时间:2018-10-28 03:20:52

标签: javascript reactjs react-hooks

使用useState钩子时出现此错误。我使用的是基本格式,请查看react docs以获得参考,但是仍然出现此错误。我已经准备好面对手掌的时刻...

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

18 个答案:

答案 0 :(得分:34)

更新时间:2018年12月

link现已发布新版本的react-hot-loader。 Hooks现在可以立即使用。感谢作者theKashey。

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

  • 反应钩
  • 反应热加载器
  • Webpack,Babel,ESLint Airbnb

上一个答案:

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

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

就我而言,禁用热加载器,HMR可以使其正常工作。

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

引用:

  

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

     

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

     

“ hotReplacementRender”。 RHL正在尝试做React的工作,并渲染   新旧应用合并。所以,显然,这是坏的   现在。

     

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

有一个更合适的解决方案,它可以工作-cold API

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

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

cold(MyComponent);

在组件源代码中搜索"useState/useEffect",并将其“冷”。

已更新:

根据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进行更新。

答案 1 :(得分:23)

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

答案 2 :(得分:3)

我在使用Parcel's Hot Module Replacement时遇到此错误,并通过将react-dom更新为Alpha版本来解决:

yarn add react-dom@16.7.0-alpha.0

See this issue.

答案 3 :(得分:2)

对我来说,问题确实是react-hot-loader

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

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

export const YourComponent = cold(() => {

  // ... hook code

  return (
    // ...
  )
})

OR

export default cold(YourComponent)

答案 4 :(得分:2)

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

<Route render={ComponentUsingHooks} />

代替

<Route component={ComponentUsingHooks} />

答案 5 :(得分:2)

对于那些在使用MobX并用Bar包装组件时遇到此问题的人,请确保使用#include <iostream> #include <memory> class Foo { public: virtual ~Foo() = default; // don't forget to add this when using polymorphism virtual void say() const { std::cout << "Foo\n"; } }; class Bar : public Foo { public: virtual void say() const { std::cout << "Bar\n"; } }; int main() { constexpr bool condition = false; auto foo = condition ? std::make_unique<Foo>() : std::make_unique<Bar>(); foo->say(); // outputs "Bar" now return 0; } 而不是observer

答案 6 :(得分:1)

我能够通过在组件文件中导入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库耦合,从而可以进行更自然的功能编程和测试。

答案 7 :(得分:1)

找到了react-hot-loader的此解决方法,而PR则修复了该问题。

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

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

解决方案的信用: https://github.com/gatsbyjs/gatsby/issues/9489

答案 8 :(得分:0)

2021 年 6 月答案

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

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

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

这个命令完成了工作!

yarn add react@latest react-dom@latest

答案 9 :(得分:0)

在我的情况下,我正在useEffect内调用useSelector!

答案 10 :(得分:0)

使用npm链接时遇到此问题的另一种解决方案:

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

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

答案 11 :(得分:0)

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

  • 包装
    • foo
      • 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是在互联网上下载的精美的情感行李的集合。

答案 12 :(得分:0)

对我来说,发生这种情况是因为我有一个新版本的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)可以修复错误。

答案 13 :(得分:0)

仅详细说明@ rista404的答案,包括react(甚至可能是react-dom重复版本)会产生相同的错误,具体取决于您使用钩子的位置。这是两个例子...

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

像这样使用webpackresolve.alias捆绑在一起时,可以解决后者...

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

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

答案 14 :(得分:0)

我的问题如下:

我正在做: AndroidManifest.xml

我应该一直在做: ReactDOM.render(Example(), app);

答案 15 :(得分:0)

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

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

这种组合效果很好。

答案 16 :(得分:0)

我在monorepo中遇到了一个问题,其中一个软件包docz使用了react@16.6.3,最后的输出包有两个React版本。

Issue on Github

通过删除软件包来修复它

答案 17 :(得分:-4)

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