React调用useState触发Invalid hook call报错
问题背景
React项目开发中遇到如下场景:
- 使用
useState存储API接口返回的响应数据 - 接口请求成功后,提取所需字段,通过
map方法遍历处理生成新数组arr - 数组处理完成后,调用
useState返回的setData方法更新data状态 - 代码运行时抛出错误:"Invalid hook call. Hooks can only be called inside of the body of a function component",翻译为:无效的Hook调用:Hook只能在函数组件的函数体内部调用
异常代码片段
import {useEffect, useState} from 'react' import logo from './logo.svg'; import './App.css'; import axios from 'axios' import ReactSearchBox from 'react-search-box' // 问题点:冗余的错误导入 import { set } from 'express/lib/application'; function App() { let [data, setData] = useState() useEffect(onMount,[]) function onMount(){ axios.get('https://restcountries.com/v3.1/all').then(res=>{ let arr = res.data.map((c)=>{ return {key:c.name.common, value: c.name.common} }) setData(arr) }) }
报错原因
- 核心诱因是代码中存在编辑器自动补全时误加的冗余导入:
import { set } from 'express/lib/application'。express是服务端Node.js框架,内部依赖大量Node环境专属API,无法在浏览器端运行,这行完全无用的导入会导致打包后的代码运行逻辑异常,干扰React运行时的Hook调用校验机制,最终抛出无效Hook调用的错误。 - 存在隐藏渲染错误:
useState()未传入初始值,data初始状态为undefined,组件首次渲染执行data.length > 0判断时,会尝试在undefined上读取length属性,触发类型错误。 - 若删除错误导入后仍复现报错,大概率是项目存在React多实例、React与ReactDOM版本不匹配问题,这类问题也会触发相同的Hook报错。
修复方案
- 直接删除无效的express相关导入行,前端业务代码不需要引入任何express模块。
- 给
useState传入空数组作为初始值,将状态声明修改为const [data, setData] = useState([]),规避首次渲染时的undefined属性访问错误。 - 若仍存在报错,检查项目依赖的React版本一致性:
- npm项目执行命令:
npm ls react - yarn项目执行命令:
yarn list react
确保依赖树中仅存在一个版本的react,且react与react-dom版本完全对应。若存在多版本冲突,删除node_modules目录和依赖锁文件后重新执行依赖安装即可。
- npm项目执行命令:
修复后完整代码
import "./styles.css"; import axios from 'axios' import ReactSearchBox from 'react-search-box' import {useEffect, useState} from 'react' export default function App() { const [data, setData] = useState([]) useEffect(() => { axios.get('https://restcountries.com/v3.1/all').then(res=>{ let arr = res.data.map((c)=>{ return {key:c.name.common, value: c.name.common} }) setData(arr) }) }, []) return ( <div className="App"> <h1>Countries</h1> {data.length > 0 ? <ReactSearchBox placeholder="Placeholder" value="Doe" data={data} callback={(record) => console.log(record)} />: null} </div> ); }
内容的提问来源于stack exchange,提问作者Amaan Imtiyaz
相关产品推荐
相关产品推荐

