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@next
和 react-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
找到 react-hot-loader
的解决方法,而修复它的 PR 是入站的。
将调用 hooks 的函数包装在 React.memo
中,防止在未更改的情况下进行热重载。
const MyFunc = React.memo(({props}) => {...
我在 monorepo 中遇到问题,其中包 docz 使用 react@16.6.3
并且最终输出包有两个反应版本。
通过删除包修复了它
更新 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
)的重复版本 会产生相同的错误,具体取决于您在哪里正在使用你的钩子。这里有两个例子...
- 外部依赖项在其
dependencies
中包含另一个版本的 react
,这可能是错误的,因为 react
通常应该是对等依赖项。如果 npm
没有自动将此版本与您的本地版本进行重复数据删除,您可能会看到此错误。这就是@rista404 所指的。
- 您
npm link
一个在其 devDependencies
或 dependencies
中包含 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)。
同时升级到@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无法在我的项目中使用,经过大量搜索后,我可以解决问题:
我刚刚将 react
和 react-dom
升级到最新版本。
这个命令完成了工作!
yarn add react@latest react-dom@latest
检查 react
和 react-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>
我在使用 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@next
和 react-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
找到 react-hot-loader
的解决方法,而修复它的 PR 是入站的。
将调用 hooks 的函数包装在 React.memo
中,防止在未更改的情况下进行热重载。
const MyFunc = React.memo(({props}) => {...
我在 monorepo 中遇到问题,其中包 docz 使用 react@16.6.3
并且最终输出包有两个反应版本。
通过删除包修复了它
更新 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
)的重复版本 会产生相同的错误,具体取决于您在哪里正在使用你的钩子。这里有两个例子...
- 外部依赖项在其
dependencies
中包含另一个版本的react
,这可能是错误的,因为react
通常应该是对等依赖项。如果npm
没有自动将此版本与您的本地版本进行重复数据删除,您可能会看到此错误。这就是@rista404 所指的。 - 您
npm link
一个在其devDependencies
或dependencies
中包含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)。
同时升级到@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无法在我的项目中使用,经过大量搜索后,我可以解决问题:
我刚刚将 react
和 react-dom
升级到最新版本。
这个命令完成了工作!
yarn add react@latest react-dom@latest
检查 react
和 react-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>