首页 > 解决方案 > 带有 Typescript 的类组件中的 React.useContext:无法解析类装饰器的签名

问题描述

我正在尝试在我的类组件中使用 React.createContext 添加一个商店。

我的应用程序设置如下:

const someStore = new SomeStore();


export const StoreContext = React.createContext(someStore);

export interface IProps  {
    store: SomeStore;
    children: any;
};
export const StoreProvider = ({ children }: any) => {
  return (
    <StoreContext.Provider value={someStore}>{children}</StoreContext.Provider>
  );
};

export const useStore = () => React.useContext(StoreContext);
 
export const withStore = (Component: React.ComponentType<IProps> ) => (props: IProps) => {
  return <Component {...props} store={useStore()} />;
};

ReactDOM.render(
    <React.StrictMode>
        <StoreProvider>
        <App />
        </StoreProvider>    
    </React.StrictMode>,
    document.getElementById('root'),
);

我尝试使用 withStore 装饰器来使用商店:

@observer
@withStore
export default class HomeContainer extends React.Component<IProps> {    
    public render() {       
        return (
            <div>
                <Navbar />
                <h2>This is {this.props.store.helloWorld}</h2>
            </div>
        );
    }
}

Typescript 在@withStore 上抱怨以下错误:

Unable to resolve signature of class decorator when called as an expression.
  Type '(props: IProps) => JSX.Element' is not assignable to type 'typeof HomeContainer'.
    Type '(props: IProps) => Element' provides no match for the signature 'new (props: Readonly<IProps>): HomeContainer'.  TS1238

    14 | // })
    15 | @observer
  > 16 | @withStore
       | ^
    17 | export default class HomeContainer extends React.Component<IProps> {   
    18 |    // static contextType = StoreContext;
    19 |    //context: React.ContextType<typeof StoreContext>;    

似乎这只是一个找到正确接口的问题..

标签: reactjstypescript

解决方案


问题有两个方面:

  • with-decorator 签名的问题
  • 上下文设置需要在单独的文件中

工作解决方案:

应用程序/上下文.ts

export const StoreContext = React.createContext(someStore);

export interface IProps {
    store?: GlobalStore;
};

export const useStore = () => React.useContext(StoreContext);
export const withStore = (WrappedComponent: any): any => {
    return class extends React.Component<IProps> {
        render() {
            return <StoreContext.Consumer>
                { ctx => <WrappedComponent store={ctx} {...{ ...this.props, ...this.state }} />}                
            </StoreContext.Consumer>    
        }
    }
};

应用程序.tsx

import { StoreContext, someStoreInstance} from 'app/context';
ReactDOM.render(
    <React.StrictMode>
        <StoreContext.Provider value={someStoreInstance}>
            <App />
        </StoreContext.Provider>
    </React.StrictMode>,
    document.getElementById('root'),
);

HomeContainer.tsx 中的用法

@withStore
@observer
export default class HomeContainer extends React.Component<IProps> {    
    constructor(props: IProps) {
        super(props);
    }
    public render() {       
        return (    
            <div>
                <h2>This is {this.props.store.helloWorld}</h2>
            </div>
        );
    }
}

推荐阅读