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


78

使用useState挂钩时出现此错误。我有它的基本形式,正在看react docs作为参考,但是仍然出现此错误。我已经准备好面对手掌的时刻...

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

2
对我有用...没有错误...您更新到16.7吗?
SakoBu

是啊,我做了。我在想也许它与我的设置有其他关系,但我不知道该怎么办。如果我在功能App组件顶部使用相同的钩子,则会发生相同的错误。
loganfromlogan '18 -10-28

嗯...我所做的就是npx create-react-app newhook,然后在纱上添加react @ next和react-dom @ next,效果很好...
SakoBu

8
只需结束一个FYI,您就需要将React和ReactDOM都更新为@next,以使钩子起作用。如果您不这样做,则react会抛出上述错误。我知道,因为我只是遇到了这个问题,这就是我的解决方案。
托尼

Answers:


40

更新时间:2018年12月

的新版本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组件。原因是-只要SFC上没有“更新”方法,就可以在HMR上强制更新。我正在寻找强制更新的其他方式(像这样。所以RHL正在杀死SFC。

“ hotReplacementRender”。RHL正在尝试做React的工作,并渲染新旧应用,以将它们合并。所以,显然,这已经被打破了。

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

有一个更合适的修复程序将起作用-冷API

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

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

cold(MyComponent);

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

更新:

根据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
});

感谢@loganfromlogan的更新。


感谢您指出这一点:)。我正在使用react-hot-loader,因此这是行不通的。但是,我还不确定100%是否也没有其他事情发生。我将在react-hot-loader上关注此问题,并在发布修复程序后更新此问题。
loganfromlogan '18 -10-29

现在,我可以确认禁用react-hot-loader已解决此错误。
loganfromlogan '18 -10-30

2
补充一点,如果有任何机会将组件呈现为内联jsx函数调用,即使将组件包装为,它仍然会导致错误cold。因此{MyComponent(props)}不会起作用,但是<MyComponent {...props} />会起作用。
Dimitar Nikovski

现在有一种方法可以使它与react-hot-loader一起使用。请参阅react-hot-loader维护者的评论github.com/gaearon/react-hot-loader/issues/…–
loganfromlogan


15

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

<Route render={ComponentUsingHooks} />

代替

<Route component={ComponentUsingHooks} />

1
这句话也救了我一命。浪费了3个小时,把我的项目弄成碎片。是路由器中的错字
Ben Gannaway

3

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



3

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

在Github上发行

通过移除包装进行固定😅


2

对我来说,问题的确是反应热装载器

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

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

export const YourComponent = cold(() => {

  // ... hook code

  return (
    // ...
  )
})

要么

export default cold(YourComponent)

2

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

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

后者可以像这样webpack使用时固定在一起resolve.alias...

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

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




1

我的问题是:

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

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


1
这也是我的问题,我很高兴在这里找到答案。
塞斯·布罗

这也是我的问题,我很高兴在这里找到答案。我怀疑这是我自己的原因造成的一些微妙的愚蠢,但是由于显然捆绑器中的模块重复 存在一些实际问题,因此我进行了为时4小时的研究。乐于恢复我的理智,以牺牲我的自尊心为代价。
塞斯·布罗

1

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

  • 包装
      • react@16.8.6
    • 酒吧
      • 反应@ 16.10.1

关于Invalid Hook Call Warning的Facebook文档对纱线工作区一无所知,因此我认为我的配置正确。但事实并非如此。您只能通过在所有软件包中使用相同版本来解决该错误。

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

奖励:请在GitHub上查看此讨论,以获取在互联网上分载的美丽情感包。



0

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

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

这种组合效果很好。




-5

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


“ react”:“ ^ 16.7.0-alpha.0”,“ react-dom”:“ ^ 16.7.0-alpha.0”,
shisongyan

5
如果答案仅是建议,则可以使用注释部分
AirCodeOne
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.