首页 > 解决方案 > 如何使用 Firebase 和 TypeScript 构建 HOC 上下文?

问题描述

我在使用 Firebase 进行身份验证的 React 应用程序中使用 TypeScript。在使用 TypeScript 之前,我为 Firebase 部分使用了常规上下文,这很好。但是,现在我已经添加了 TypeScript,但我遇到了错误。

例如,这是我的 SignIn 组件(为简洁起见,省略了一些部分):

import React, { Component }        from 'react';
import Firebase, { withFirebase }  from '../Firebase';

const SignInForm = (firebase:Firebase) => {

  onSubmit = event => {
    ... uses firebase to handle authentication ...
  };


  render() {
 
    return (
      <form onSubmit={handleSubmit}>
       ... sign in form ...
      </form>
    );
  }
}

export default withFirebase(SignInForm);

在 ../Firebase 我有 index.js,其中包含:

import FirebaseContext, { withFirebase } from './context';
import Firebase from './firebase';

export default Firebase;

export { FirebaseContext, withFirebase };

./firebase.js 是:

import app from 'firebase/app';
import 'firebase/auth';

class Firebase {

  constructor() {
    app.initializeApp(config);
  }

  getUserIdToken = () => {
    if (app.auth().currentUser !== null) {
      return app.auth().currentUser?.getIdToken() as Promise<string>;
    }
    return Promise.reject("User not signed in") as Promise<string>;
  };

  ... various other firebase functions ...

}
 
export default Firebase;

和 ./context.js 是:

import React    from 'react';
import Firebase from './firebase';

const FirebaseContext = React.createContext<Firebase | null>(null);

export const withFirebase = (Component: React.ComponentClass) => (props:any) => (
  <FirebaseContext.Consumer>
    {
      firebase => <Component {...props} firebase={firebase} />
    }
  </FirebaseContext.Consumer>
)

export default FirebaseContext;

上下文提供程序位于顶层,如下所示:

import React    from 'react';
import ReactDOM from 'react-dom';

import Firebase, { FirebaseContext }  from './components/Firebase';
import App                            from './components/App';

ReactDOM.render(
  <FirebaseContext.Provider value={new Firebase()}>
    <App />
  </FirebaseContext.Provider>,
  document.getElementById('root')
);

serviceWorker.unregister();

我得到的错误是在我的 SignIn 组件的导出行中:export default withFirebase(SignInForm);。SignInForm 带有下划线,错误消息为:

Argument of type '(firebase: Firebase) => JSX.Element' is not assignable to parameter of type 'ComponentClass<{}, any>'.
  Type '(firebase: Firebase) => Element' provides no match for the signature 'new (props: {}, context?: any): Component<{}, any, any>'.

将鼠标悬停在带下划线的错误上会给我函数定义:

const SignInForm: (firebase: Firebase) => JSX.Element

所以,据我所知,问题在于 withFirebase 期望接收一个组件,但接收的是一个 JSX 元素。有没有办法在传入之前将 JSX 转换为组件?还是有另一种方法来解决这个问题?

标签: javascriptreactjstypescriptfirebase

解决方案


SignInForm对它是什么感到非常困惑。它是一个函数而不是类组件,但它有一个render()方法而不是一个return语句。它不接受作为函数组件的正确参数。它应该接受一个 props 对象,而不是接受一个名为firebase. 您需要修复SignInForm成合法的函数组件或类组件。

const SignInForm: React.FC<{firebase:Firebase}> = ({firebase}) => {
    /* ... */
    return (
      <form onSubmit={handleSubmit}>
       ... sign in form ...
      </form>
    );
}
class SignInForm extends React.Component<{ firebase: Firebase }> {
    /* ... */
    render() {
        return (
            <form onSubmit={handleSubmit}>
                ... sign in form ...
            </form>
        );
    }
}

正如当前编写的那样,您的withFirebaseHOC 只能接受一个类组件。您可以通过替换为轻松解决此React.ClassComponent问题React.ComponentType


推荐阅读