2

I have pages or large components that need to be rendered after the main page loads. I have them lazily loaded but am getting an error when I use in createElement():

LazyExoticComponent | LazyExoticComponent is not assignable to parameter of type 'string | FunctionComponent<RefAttributes> | ComponentClass<RefAttributes, any>'

What I've tested:

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

Using latest versions of Typescript, React, React-Scripts does not seem to have any affect.

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

5
  • why use createElement now when you can use JSX currently? Commented Apr 4, 2021 at 17:09
  • The example is shortened to show the big picture of what's happening with the step variable. In my actual program, the step variable is stored in state before being added to the return of render(). I'm unsure if there are benefits, but that is how I got the project from a previous group. Commented Apr 4, 2021 at 17:17
  • Error is: LazyExoticComponent<typeof Page2> | LazyExoticComponent<typeof ...> | ... is not assignable to paramter of type 'string'. Editted post to more accurately describe situation. Commented Apr 5, 2021 at 5:59
  • 1
    I understand how and why your post below works +1. I tried for an hour but couldn't replicate in sandbox. Updated post to hopefully cut out the unnecessary parts. Commented Apr 5, 2021 at 7:30
  • Seems like it. I have no idea why. Commented Apr 5, 2021 at 7:36

2 Answers 2

1

This particular problem has to do with the generics of the React.Component type. If using an array, each element page's React.Component 'signature' has to be the same or it will throw this error. For example:

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]);

This will work because the 'signatures' of Page2 and Page3 are the same. Namely, they are <>.

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

These on the other hand, will not work and are what caused the issue I posted about. Even if IPage3Props and IPage2Props have the same contents in the interface/type, it TS will still not understand.

This issue, as far as I can tell, does not have anything to do with the environment or the versions of TS, or React used.

The obvious solution is to make the 'signatures' the same. This may not be practical and I am unsure what else can be done to fix the issue.

Sign up to request clarification or add additional context in comments.

2 Comments

If you lost the email address of your original account, you can flag one of your posts for moderator attention, or click the "Contact us" button at the bottom of the page. In either case, explain the issue clearly so that your accounts can be merged.
Yes. It is related to Typings. Lazy and Suspense would work as normal.
-1

You can simply use lazy and Suspense with a fallback content.

The lazy component should then be rendered inside a Suspense component, which allows us to show some fallback content (such as a loading indicator) while we’re waiting for the lazy component to load.

An example:

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>
      </>
    );
  }
}

Here is CodeSandbox

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.