reactjs - React-koddelning i React.createElement()


Jag har sidor eller stora komponenter som behöver renderas efter att huvudsidan har laddats. Jag har dem laddade på begäran men får ett fel när jag använder dem i createElement():

LazyExoticComponent | LazyExoticComponent kan inte tilldelas till parameter av typen 'string | FunctionComponent | ComponentClass'

Vad jag har testat:

import Page2 from "./Page2";
import Page3 from "./Page3";
const pages = [Page2, Page3];

//in any method in the react component
let s = [Page2];
let ss = [Page2, Page3];
let sss = pages[0];
let r = React.createElement(s[0]); //this works
let rr = React.createElement(ss[0]); //does not work
let rrr = React.createElement(sss); //does not work

Att använda de senaste versionerna av Typescript verkar inte ha någon effekt på React eller React-Scripts.

Typescript ^3.9.9, React ^16.14.0, React-Scripts ^2.1.8, "@types/react": "^17.0.0", "react-dom": "^16.13.1", inga @types/react-dom

Svar #1

Detta specifika problem har att göra med generics i typen React.Component. Om man använder en array måste varje elements React.Component-‘signatur’ vara densamma, annars kommer det att ge detta fel. Till exempel:

export default class Page2 extends React.Component {...}
export default class Page3 extends React.Component {...}

//in main file
const Page2 = lazy( ()=>import('./Page2') );
const Page3 = lazy( ()=>import('./Page3') );
const pages = [Page2, Page3];
...
let page = React.createElement(pages[1]);

Detta kommer att fungera eftersom 'signaturerna' för Page2 och Page3 är desamma. Nämligen, de är <>.

export default class Page2 extends React.Component<IPage2Props, IPage2State>
export default class Page3 extends React.Component<IPage3Props, IPage3State>

Dessa å andra sidan kommer inte att fungera och är vad som orsakade problemet jag skrev om. Även om IPage3Props och IPage2Props har samma innehåll i gränssnittet/typen, kommer TypeScript fortfarande inte att förstå.

Det här problemet, såvitt jag kan se, har inget att göra med miljön eller versionerna av TS eller React som används.

Den uppenbara lösningen är att göra 'signaturerna' likadana. Detta kanske inte är praktiskt och jag är osäker på vad mer som kan göras för att åtgärda problemet.

Svar #2

Du kan helt enkelt använda lazy och Suspense med ett ersättningsinnehåll.

Den lata komponenten bör sedan renderas inuti en Suspense-komponent, vilket gör att vi kan visa något ersättningsinnehåll (såsom en laddningsindikator) medan vi väntar på att den lata komponenten ska laddas.

Ett exempel:

import React, { Component, createElement, lazy, Suspense } from "react";

const Page2 = lazy(() => import("./Page2"));
const Page3 = lazy(() => import("./Page3"));

const pages = [Page2, Page3];

class App extends Component {

  render() {
    let s = [Page2];
    let ss = [Page2, Page3];
    let sss = pages[0];
    let r = createElement(s[0]);
    let rr = createElement(ss[0]);
    let rrr = createElement(sss);
    return (
      <>
        <h2>App</h2>
        <Suspense fallback="loading..."> {/* <== using the Suspense /*}
          {r} {rr} {rrr}
        </Suspense>
      </>
    );
  }
}

Här är CodeSandbox