首页 > 解决方案 > 如何在 React 中将 JSX 元素转换为函数组件?

问题描述

我的 React 应用在 App.js 中有以下内容:

const App = () => (
  <Router>
    <Switch>
       ... various routes, all working fine ...
      <Route exact path={ROUTES.DASHBOARD} render={(props) => <Dashboard {...props} />}/>
    </Switch>
  </Router>
);

我在仪表板上收到一个错误,上面写着JSX element type 'Dashboard' does not have any construct or call signatures.

这是因为Dashboard是这样创建的:

const DashboardPage = ({firebase}:DashboardProps) => {
  
  return (
    <div className="mainRoot dashboard">...contents of dashboard...</div>
  );
}

const Dashboard = withFirebase(DashboardPage);
export default Dashboard;

并且withFirebase是:

从'./firebaseContext'导入FirebaseContext;

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

export default withFirebase;

所以 withFirebase 正在导出一个 JSX 元素,这就是 Dashboard。如何确保 withFirebase 正在导出组件?

标签: javascriptreactjstypescript

解决方案


所以 withFirebase 正在导出一个 JSX 元素,这就是 Dashboard。如何确保 withFirebase 正在导出组件?

withFirebase不是创建 JSX 元素,而是创建一个创建 JSX 元素的函数——换句话说,它是一个函数组件。也许它有助于正确键入它。

const withFirebase = <Props extends {}>(
  Component: React.ComponentType<Omit<Props, "firebase"> & { firebase: Firebase | null }>
): React.FC<Props> => (props) => (
  <FirebaseContext.Consumer>
    {(firebase) => <Component {...props} firebase={firebase} />}
  </FirebaseContext.Consumer>
);

这些类型在这个答案中有详细解释。你的上下文值有时null吗?你能DashboardPage处理吗,还是我们需要在这里处理?这是确保DashboardPage只能使用有效Firebase道具调用的一种方法。

const withFirebase = <Props extends {}>(
  Component: React.ComponentType<Omit<Props, "firebase"> & { firebase: Firebase }>
): React.FC<Props> => (props) => (
  <FirebaseContext.Consumer>
    {(firebase) =>
      firebase ? (
        <Component {...props} firebase={firebase} />
      ) : (
        <div>Error Loading Firebase App</div>
      )
    }
  </FirebaseContext.Consumer>
);

现在我们已经修复了 HOC,您的Dashboard组件具有 type React.FC<{}>。它是一个不带任何道具的功能组件。

你不需要render为你创建一个内联方法Route(这实际上会给出关于不兼容道具的错误)。您可以将其设置为component属性component={Dashboard}

完整代码:

import React from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";

// placeholder
class Firebase {
  app: string;

  constructor() {
    this.app = "I'm an app";
  }
}

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

const withFirebase = <Props extends {}>(
  Component: React.ComponentType<Omit<Props, "firebase"> & { firebase: Firebase }>
): React.FC<Props> => (props) => (
  <FirebaseContext.Consumer>
    {(firebase) =>
      firebase ? (
        <Component {...props} firebase={firebase} />
      ) : (
        <div>Error Loading Firebase App</div>
      )
    }
  </FirebaseContext.Consumer>
);

interface DashboardProps {
  firebase: Firebase;
}

const DashboardPage = ({ firebase }: DashboardProps) => {
  console.log(firebase);
  return <div className="mainRoot dashboard">...contents of dashboard...</div>;
};

const Dashboard = withFirebase(DashboardPage);

const App = () => {
  const firebase = new Firebase();
  return (
    <FirebaseContext.Provider value={firebase}>
      <Router>
        <Switch>
          <Route component={Dashboard} />
        </Switch>
      </Router>
    </FirebaseContext.Provider>
  );
};

export default App;

推荐阅读