Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot import async components: Undefined component passed to createElement() #1293

Closed
heokhe opened this issue Jul 6, 2020 · 15 comments
Closed

Comments

@heokhe
Copy link

heokhe commented Jul 6, 2020

Do you want to request a feature or report a bug?
It's a bug.

What is the current behaviour?
I'm trying to load a component from src/components/async directory, and get this error:

Uncaught Error: Undefined component passed to createElement()

You likely forgot to export your component or might have mixed up default and named imports<#text dangerouslySetInnerHTML="[object Object]" />

  in #text
  in AsyncComponent
  in App

If the current behaviour is a bug, please provide the steps to reproduce.

// src/components/async/Hello.js
export default function Hello() {
  return <h1>hello</h1>
}
// src/index.js
import Hello from './components/async/Hello'
export default function App() {
  return <Hello />
}

What is the expected behaviour?
Load the component Hello as an async component.

Please mention other relevant information.

Please paste the results of preact info here.

Environment Info:
  System:
    OS: Linux 5.4 Ubuntu 20.04 LTS (Focal Fossa)
    CPU: (2) x64 AMD A9-9410 RADEON R5, 5 COMPUTE CORES 2C+3G
  Binaries:
    Node: 14.2.0 - /usr/local/bin/node
    Yarn: 1.7.0 - ~/.npm-global/bin/yarn
    npm: 6.14.4 - /usr/local/bin/npm
  Browsers:
    Chrome: 83.0.4103.116
    Firefox: 77.0.1
  npmPackages:
    preact: ^10.3.2 => 10.3.3 
    preact-cli: ^3.0.0-rc.16 => 3.0.0-rc.16 
  npmGlobalPackages:
    preact-cli: 3.0.0-rc.16
@heokhe heokhe changed the title Cannot load from src/component/async: Undefined component passed to createElement() Cannot import from src/component/async: Undefined component passed to createElement() Jul 6, 2020
@heokhe
Copy link
Author

heokhe commented Jul 8, 2020

Update: async! prefix doesn't work too.

@heokhe heokhe changed the title Cannot import from src/component/async: Undefined component passed to createElement() Cannot import async components: Undefined component passed to createElement() Jul 8, 2020
@rschristian
Copy link
Member

I assume that, while this warning shows up in your console, the component does render? As that is what I can reproduce.

One solution could be to use Lazy & Suspense. While marked as experimental, it does seem to suppress that warning.

import { Suspense, lazy } from 'preact/compat';
const Hello = lazy(() => import('./components/async/Hello'));

export default function App() {
    return (
        <Suspense fallback={<div>loading...</div>}>
            <Hello />
        </Suspense>
    )
}

@heokhe
Copy link
Author

heokhe commented Jul 8, 2020

It actually prevents other things from rendering. I can't reproduce it now but it tried it in a bigger application.

I've also noticed that downgrading to 3.0.0-rc.14 solves the problem.

@heokhe
Copy link
Author

heokhe commented Jul 8, 2020

Found a better way to reproduce this:

// src/index.js
import Hello from './components/async/Hello'
export default function App() {
  return <>
    <Hello />
    <div>This won't be rendered.</div>
  </>
}

But if you use an element instead of fragments the error will be gone.

@reznord
Copy link
Member

reznord commented Jul 8, 2020

@hkh12 can you just reproduce this in a repo and share if possible?

@heokhe
Copy link
Author

heokhe commented Jul 8, 2020

@reznord
Copy link
Member

reznord commented Jul 8, 2020

Awesome, thanks. Will look into it now.

developit added a commit that referenced this issue Jul 9, 2020
I finally (FINALLY) found a solution for #1293, #1308, etc etc. This doesn't use DOM hacks or anything - it just crawls up the tree of VNodes and performs a Depth-First-Search backwards from the position of AsyncComponent in order to find the most recently hydrated DOM element. Essentially, the first populated `vnode._dom` reference it finds is guaranteed to be the previous sibling of the parent element AsyncComponent is about to get rendered into. As long as AsyncComponent isn't being used load a component that renders a Fragment, the nextSibling of that discovered element is the exact node Preact will try to hydrate.

In the case of an AsyncComponent wrapping a Fragment, only the first Fragment child will be hydrated. This means the remaining children will have the flicker effect, but that's pretty reasonable:

```js
// app.js
import Foo from 'async!./foo';
export default () => <div><Foo /></div>

// foo.js
export default () => <Fragment>
    <h1>Hello</h1>
    <p>world!</p>  // will be culled+reinserted during hydration
</Fragment>
```
reznord added a commit that referenced this issue Jul 9, 2020
* Fix async-loader for Preact X

I finally (FINALLY) found a solution for #1293, #1308, etc etc. This doesn't use DOM hacks or anything - it just crawls up the tree of VNodes and performs a Depth-First-Search backwards from the position of AsyncComponent in order to find the most recently hydrated DOM element. Essentially, the first populated `vnode._dom` reference it finds is guaranteed to be the previous sibling of the parent element AsyncComponent is about to get rendered into. As long as AsyncComponent isn't being used load a component that renders a Fragment, the nextSibling of that discovered element is the exact node Preact will try to hydrate.

In the case of an AsyncComponent wrapping a Fragment, only the first Fragment child will be hydrated. This means the remaining children will have the flicker effect, but that's pretty reasonable:

```js
// app.js
import Foo from 'async!./foo';
export default () => <div><Foo /></div>

// foo.js
export default () => <Fragment>
    <h1>Hello</h1>
    <p>world!</p>  // will be culled+reinserted during hydration
</Fragment>
```

* Stop searching if we hit an element parent

Co-authored-by: Anup <allamsetty.anup@gmail.com>
@reznord
Copy link
Member

reznord commented Jul 9, 2020

@hkh12 this is resolved in the latest rc (3.0.0-rc.17) today.

Feel free to re-open if you are still facing the issue 🙂

@reznord reznord closed this as completed Jul 9, 2020
@heokhe
Copy link
Author

heokhe commented Jul 10, 2020

Still facing the issue. I committed the updates to https://github.com/hkh12/preact-cli-bug-1293

@gokatz
Copy link

gokatz commented Aug 20, 2020

facing this issue in preact:10.4.7, preact-cli: 3.0.1. downgrading preact CLI helped.

@FranciscoG
Copy link

FranciscoG commented Dec 12, 2020

also facing this issue:

  • preact@10.5.7
  • preact-router@3.2.1
  • preact-cli@3.0.5

trying to replicate it in a codesandbox but can't seem to
https://codesandbox.io/s/hopeful-aryabhata-1ynnj?file=/src/app.js

@cyclops26
Copy link

also facing this issue:

  • preact@10.5.7
  • preact-router@3.2.1
  • preact-cli@3.0.5

trying to replicate it in a codesandbox but can't seem to
https://codesandbox.io/s/hopeful-aryabhata-1ynnj?file=/src/app.js

@FranciscoG did you find a resolution/or the issue? I'm running into this with the following packages, but like you in a sandbox it works. I've tried multiple node versions and started with a clean package-lock file and clean node_modules direction to no avail.

  • preact@10.5.10
  • preact-router@3.2.1
  • preact-cli@3.0.5

@cyclops26
Copy link

I found that the resolution for me was to not use a second component declared within the same file and only to use imported components.... not sure why this was an issue though.

@hinst
Copy link

hinst commented Jun 20, 2024

I am just getting started with Preact and I ran into this error when I tried to use my class component

🐞Uncaught Error: Invalid type passed to createElement(): [object Object]

import { Component, ComponentChild, RenderableProps } from "preact";

interface ParameterTypesProps {
}

interface ParameterTypesState {
}

export class ParameterTypesPanel extends Component<ParameterTypesProps, ParameterTypesState> {
    constructor() {
        super({});
        this.state = {};
    }

    render(props?: RenderableProps<ParameterTypesProps, any>, state?: Readonly<ParameterTypesState>, context?: any): ComponentChild {
        return <div></div>;
    }
}

index.tsx:

export function App() {
	return (
		<LocationProvider>
			<Header />
			<main>
				<Router>
					<Route path='/' component={Home} />
					<Route path='/ParameterTypes' component={new ParameterTypesPanel} />
					<Route default component={NotFound} />
				</Router>
			</main>
		</LocationProvider>
	);
}

Does someone by chance have an idea what is wrong here? And why is there no diagnostics information coming from Preact in the error message. Stack trace is not visible in browser console

@rschristian
Copy link
Member

rschristian commented Jun 20, 2024

@hinst preact-cli is no longer maintained, see the warning at the top of the ReadMe.

Please switch to a supported tool, like a Vite via create-preact.

Edit: Never invoke/create components directly. Switch new ParameterTypesPanel to ParameterTypesPanel

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants