TypeScript类组件全局状态实现及Hook调用报错解决
问题原因
你遇到的错误是因为React Hook只能在函数组件或自定义Hook中调用,类组件不支持直接使用Hook,这是React Hook的核心规则之一。以下是几种适配类组件的解决方案:
解决办法1:将类组件转为函数组件(推荐)
React官方推荐函数组件+Hook的写法,代码更简洁且符合现代React最佳实践,直接适配你已有的Context实现:
page.tsx 改造后
import { useGlobalState, GlobalStateInterface } from "../../app/GlobalStateProvider"; import { useForm } from "react-hook-form"; const PageComponent = () => { const { setState } = useGlobalState(); const { handleSubmit } = useForm(); const submitFunction = async (data: Partial<GlobalStateInterface>) => { // 设置状态为指定内容 setState((prev) => ({ ...prev, abcstring: "操作中..." })); try { // 执行你的业务逻辑(比如文件上传等异步操作) // await yourAsyncUploadLogic(); } finally { // 方法结束后重置为null setState((prev) => ({ ...prev, abcstring: null })); } }; const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => { // 你的文件处理逻辑 }; return ( <> <input accept=".csar,.yaml" id="file" min={1} max={1} multiple={false} type="file" name="abc" onChange={handleFileChange} /> <label htmlFor="file"> <form onSubmit={handleSubmit(submitFunction)}> <Button className={inputUploadButton} component="span" variant="primary" type="submit" isSmall onClick={(e) => e.stopPropagation()} > <Tooltip key={`Upload`} content={<div>Upload</div>}> <UploadIcon /> </Tooltip> </Button> </form> </label> </> ); }; export default PageComponent;
Page2.tsx 改造后
import { useGlobalState } from "../../../app/GlobalStateProvider"; const Page2Component = () => { const { state } = useGlobalState(); return ( <> <ToolbarItem> {console.log(state.abcstring)} {state.abcstring === "操作中..." ? ( <Title sizes={'sm'} headingLevel={'h6'}> operation in progress... </Title> ) : null} </ToolbarItem> </> ); }; export default Page2Component;
解决办法2:使用Context.Consumer(保留类组件)
如果不想改造类组件结构,可以直接用GlobalStateContext.Consumer在类组件的render方法中获取上下文:
Page2.tsx 修改后
import React from "react"; import { GlobalStateContext } from "../../../app/GlobalStateProvider"; class ClassName2 extends React.Component { render() { return ( <GlobalStateContext.Consumer> {({ state }) => ( <> <ToolbarItem> {console.log(state.abcstring)} {state.abcstring === "操作中..." ? ( <Title sizes={'sm'} headingLevel={'h6'}> operation in progress... </Title> ) : null} </ToolbarItem> </> )} </GlobalStateContext.Consumer> ); } } export default ClassName2;
page.tsx 修改后(拆分表单逻辑为子组件)
import React from "react"; import { GlobalStateContext, GlobalStateInterface } from "../../app/GlobalStateProvider"; import { useForm } from "react-hook-form"; // 抽离表单提交逻辑为函数组件(适配useForm Hook) const SubmitButton = () => { const { handleSubmit } = useForm(); return ( <GlobalStateContext.Consumer> {({ setState }) => { const submitFunction = async (data: Partial<GlobalStateInterface>) => { setState((prev) => ({ ...prev, abcstring: "操作中..." })); try { // 执行业务逻辑 } finally { setState((prev) => ({ ...prev, abcstring: null })); } }; return ( <form onSubmit={handleSubmit(submitFunction)}> <Button className={inputUploadButton} component="span" variant="primary" type="submit" isSmall onClick={(e) => e.stopPropagation()} > <Tooltip key={`Upload`} content={<div>Upload</div>}> <UploadIcon /> </Tooltip> </Button> </form> ); }} </GlobalStateContext.Consumer> ); }; export class ClassName extends React.Component { handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => { // 文件处理逻辑 }; render() { return ( <> <input accept=".csar,.yaml" id="file" min={1} max={1} multiple={false} type="file" name="abc" onChange={this.handleFileChange} /> <label htmlFor="file"> <SubmitButton /> </label> </> ); } } export default ClassName;
解决办法3:基于React-Redux实现(适配你的技术栈)
既然你的应用是基于React-Redux构建的,也可以直接用Redux管理该全局状态,类组件通过connect高阶组件连接store:
1. 定义Redux Action和Reducer
// actions.ts export const SET_GLOBAL_STATE = 'SET_GLOBAL_STATE'; export const RESET_GLOBAL_STATE = 'RESET_GLOBAL_STATE'; export const setGlobalState = (payload: Partial<GlobalStateInterface>) => ({ type: SET_GLOBAL_STATE, payload, }); export const resetGlobalState = (keys: string[]) => ({ type: RESET_GLOBAL_STATE, payload: keys, }); // reducer.ts import { SET_GLOBAL_STATE, RESET_GLOBAL_STATE } from './actions'; const initialState: Partial<GlobalStateInterface> = { abcstring: null, xyzstring: null, }; export const globalReducer = (state = initialState, action: any) => { switch (action.type) { case SET_GLOBAL_STATE: return { ...state, ...action.payload }; case RESET_GLOBAL_STATE: return action.payload.reduce((acc: any, key: string) => { acc[key] = null; return acc; }, { ...state }); default: return state; } };
2. 类组件中使用connect
page.tsx
import React from "react"; import { connect } from "react-redux"; import { setGlobalState, resetGlobalState } from "./actions"; import { useForm } from "react-hook-form"; // 抽离提交逻辑为函数组件 const SubmitButton = ({ setGlobalState, resetGlobalState }) => { const { handleSubmit } = useForm(); const submitFunction = async (data) => { setGlobalState({ abcstring: "操作中..." }); try { // 执行业务逻辑 } finally { resetGlobalState(['abcstring']); } }; return ( <form onSubmit={handleSubmit(submitFunction)}> {/* 按钮代码 */} </form> ); }; const mapDispatchToProps = { setGlobalState, resetGlobalState, }; const ConnectedSubmitButton = connect(null, mapDispatchToProps)(SubmitButton); export class ClassName extends React.Component { handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => { // 文件处理逻辑 }; render() { return ( <> <input accept=".csar,.yaml" id="file" min={1} max={1} multiple={false} type="file" name="abc" onChange={this.handleFileChange} /> <label htmlFor="file"> <ConnectedSubmitButton /> </label> </> ); } } export default ClassName;
Page2.tsx
import React from "react"; import { connect } from "react-redux"; class ClassName2 extends React.Component { render() { const { abcstring } = this.props; return ( <> <ToolbarItem> {console.log(abcstring)} {abcstring === "操作中..." ? ( <Title sizes={'sm'} headingLevel={'h6'}> operation in progress... </Title> ) : null} </ToolbarItem> </> ); } } const mapStateToProps = (state) => ({ abcstring: state.global.abcstring, }); export default connect(mapStateToProps)(ClassName2);
内容的提问来源于stack exchange,提问作者Dhananjay Gahiwade
相关产品推荐
相关产品推荐

