Mobx6关联React16.8.2类组件报Hooks仅可在函数组件调用错误如何解决
问题原因
你遇到的报错是mobx-react@7.x版本和老的inject/Provider模式适配类组件时的兼容性问题,具体原因如下:
mobx-react@7.x的observer高阶组件对类组件的封装内部采用了React Hooks实现,而你同时使用了官方已废弃的inject高阶组件嵌套在observer外层,导致内部Hooks的调用位置不符合React「Hooks只能在函数组件顶层调用」的规则,触发了校验报错。- 你使用的React 16.8.2本身支持Hooks,但
inject作为外层高阶组件会改变内部observer生成的函数组件的调用层级,最终抛出异常。
解决方案
提供三种可直接落地的方案,你可以根据项目情况选择:
- 方案1:降级
mobx-react版本(无需修改业务代码,最省心)mobx-react@6.x版本的observer对类组件的实现没有依赖Hooks,完美兼容老的inject/Provider模式,直接降级依赖即可:
npm install mobx-react@6.x # 或使用yarn yarn add mobx-react@6.x
降级后现有代码不需要做任何修改即可正常运行。
- 方案2:替换为原生React Context传递store(推荐,符合Mobx官方最新规范)
Mobx官方已经不推荐使用inject/Provider模式,改用原生React Context传递store可以彻底解决兼容性问题:
- 在rootstore.tsx中新增Context定义:
import { createContext, useContext } from 'react' export const RootStoreContext = createContext<RootStore>(new RootStore({})) export const useRootStore = () => useContext(RootStoreContext)
- 修改入口文件A.tsx,替换Mobx自带的Provider为原生Context.Provider:
import { RootStoreContext } from './rootstore' const root_store = new RootStore(); ReactDOM.render( <RootStoreContext.Provider value={root_store}> <IApp /> </RootStoreContext.Provider>, document.getElementById('root'), );
- 移除所有组件的
inject封装,类组件可以用RootStoreContext.Consumer消费store,或者直接改写成函数组件用自定义Hook拿取store,示例如下:
// C.tsx 改写为函数组件示例 import { observer } from 'mobx-react' import { useRootStore } from './rootstore' const EventsEmbedSkin = observer(() => { const root_store = useRootStore() return <div></div> }) export default EventsEmbedSkin
- 方案3:使用装饰器写法(需要项目已开启装饰器支持)
如果你的项目已经开启了TypeScript装饰器配置,可以直接用装饰器语法替换高阶函数嵌套写法,规避顺序问题:
// C.tsx 修改示例 import { inject, observer } from 'mobx-react' interface Props { root_store?: RootStore; } @inject(({root_store}:{root_store:RootStore}) => ({ root_store })) @observer class EventsEmbedSkin extends React.Component<Props> { render(): JSX.Element { return <div></div> } } export default EventsEmbedSkin
内容的提问来源于stack exchange,提问作者xoriirm
相关产品推荐
相关产品推荐

