调用useContext触发Hooks非法调用错误的解决方法求助
兄弟,我一眼就看到你问题的核心了——你在类组件里调用了useContext Hook!这完全违反了React Hook的规则:Hooks只能在函数组件的顶层作用域,或者自定义Hook里使用,类组件根本不支持Hook调用,这就是你每次运行都报错的原因。
看你代码里的this.state.user、this.drawerToggleClickHandler、this.sidedrawerToggleClickHandler这些痕迹,都是类组件的典型写法,如果你在这个类组件里写了const context = useContext(GlobalContext);,那百分百会触发这个错误。
给你两个解决方案,选一个适合你的:
方案1:把类组件转换成函数组件(推荐,符合React新特性)
把你的类组件改成函数组件,用useState替代类的this.state,用useCallback处理那些点击回调函数,这样就能合法使用useContext了。举个简化的例子:
import React, { useState, useCallback, useContext } from 'react'; import { GlobalContext } from './path-to-your-global-context'; function YourComponent() { const [user, setUser] = useState(null); const [sideDrawerOpen, setSideDrawerOpen] = useState(false); const context = useContext(GlobalContext); // 这里就能合法调用了! const drawerToggleClickHandler = useCallback(() => { setSideDrawerOpen(prev => !prev); }, []); const sidedrawerToggleClickHandler = useCallback(() => { setSideDrawerOpen(false); }, []); // 剩下的render逻辑改成函数式写法... return ( <div> <Router> <div className='App'> {user ? (<Nav drawerClickHandler={drawerToggleClickHandler} />) : (<Login_bar />)} <SideDrawer sidedrawerClickHandler={sidedrawerToggleClickHandler} show={sideDrawerOpen} /> {backdrop} <GlobalProvider> {user ? ( <Switch> <Route path='/settings_page' component={settings_page} exact /> <Route path='/setup_page' component={setup_page} exact /> <Route path='/' component={Main_page} /> </Switch> ) : (<Login_page />)} </GlobalProvider> </div> </Router> </div> ); }
方案2:在类组件中用传统方式获取上下文(不想转函数组件的话)
如果暂时不想重构组件,可以用类组件支持的contextType或者Context.Consumer来获取全局上下文,代替useContext:
方式A:使用contextType
import React from 'react'; import { GlobalContext } from './path-to-your-global-context'; class YourClassComponent extends React.Component { static contextType = GlobalContext; componentDidMount() { // 在生命周期里获取上下文 const { healthData } = this.context; console.log('Health data:', healthData); } render() { // 在render里获取上下文 const { healthData } = this.context; return ( <div>你的年龄是:{healthData.age}</div> ); } }
方式B:使用Consumer组件
import React from 'react'; import { GlobalContext } from './path-to-your-global-context'; class YourClassComponent extends React.Component { render() { return ( <GlobalContext.Consumer> {context => ( <div>你的目标是:{context.healthData.goal}</div> )} </GlobalContext.Consumer> ); } }
另外,你的代码还有个小问题要修正
看你提供的GlobalContext文件,最后导出的那个reducer函数应该是AppReducer的内容,但你把它直接写在了GlobalProvider的文件里,这会导致导出混乱。建议把它移到单独的AppReducer.js文件里:
// AppReducer.js export default (state, action) => { switch(action.type) { default: return state; } }
这样你的GlobalProvider文件就只负责上下文的创建和提供,逻辑更清晰。
最后再确认下你的React和ReactDOM版本,虽然你说更新过,但还是执行下这个命令检查一下:
npm list react react-dom
确保版本号≥16.8.0(Hook首次引入的版本)。
按上面的步骤改完,你的错误应该就能解决了!
内容的提问来源于stack exchange,提问作者lukeet

