-
-
Notifications
You must be signed in to change notification settings - Fork 10.2k
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
[Bug]: lazy
factory return value is not enforced in Typescript
#10475
Comments
Was this fixed or modified somewhat?
I am just What am I doing wrong? Thank you and sorry if this is not the place, but there's almost no info about this lazy property. |
Have you reviewed https://reactrouter.com/en/main/route/lazy? Specifically, I think what you're missing is:
You are not exporting any properties, you're exporting a So if normally your route would be: <Route path="a" element={<div>Hi!</div>} /> Then you lazy module needs to export the // lazy.tsx
export const element = {<div>Hi!</div>} />;
// app.tsx
<Route path="a" lazy={() => import('./lazy')} /> When using // lazy.tsx
export function Component() {
return <div>Hi!</div>;
} |
This is fixed in #10634 and should be available in the next release after |
I followed the createBrowserRouter tutorial to create a hash router, so my App.tsx looks like this // App.tsx
// all my imports
const router = createHashRouter([
{
path: "/",
lazy: () => import('./pages/Home'),
},
// the rest of my routes
// more boilerplate code
root.render(
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>
); and my Home.tsx is declared as a functional component: export default function Home(): JSX.Element {
return (
<div>Hello World</div>
)
} and yet I still get the error I could only get this to work when I completely changed the function to a const of just a plain div, e.g. // Home.tsx
export const element = <div>Hi</div>
export default element But I cannot find any way to export a component and not have it complain about either missing default export or the same type error above. What am I doing wrong? I am using react-bootstrap components like In addition to this, can you please update your documentation for your page on lazy to show how to insert lazy calls in an object structure? Through trial and error, I found it to work when defined like this: {
path: "home",
errorElement: <ErrorPage />,
lazy: () => import('./pages/Home'),
}, Thank you, and apologies for the long comment on a closed issue, but it's been driving me nuts for how simple it should be and yet doesn't work. |
Since the object returned from When you do export function Component(): JSX.Element { ... }
``
Docs PRs are always welcome to clarify any confusion! |
@brophdawg11 How can i pass props to component? By example, i have a private route which i define the user claim needed in component props: // routes.tsx
...
<Route
path="/system"
element={<PrivateRoute allowedUserType="system" />}
>
... Then, how can i use following code with lazy? // routes.tsx
...
<Route
path="/system"
lazy={async () => await import('~components/auth/PrivateRoute')} // where to pass property allowedUserType?
>
... |
<Route path="/system" lazy={async () => {
let mod = await import('~components/auth/PrivateRoute');
return {
...mod,
Component: undefined,
element: <mod.Component allowedUserType="system" />
};
}
> |
Documentation is not clear about how to lazy load components. Thank you. This worked. So generally you have to export |
Could you elaborate on how it's unclear? Docs PRs are always welcome if there's room for improvements! Right now we keep it pretty simple with:
The idea is that you export whatever you would usually put directly on the // Before
<Route path="/" loader={someLoader} element={<SomeComponent />} />
// After - move `loader`/`element` to the lazy file
<Route path="/" lazy={() => import('./route') />
// ./route.js
export function loader() { ... }
function SomeComponent() {}
export const element = <SomeComponent />;
You do not have to export // Before
<Route path="/" loader={someLoader} Component={SomeComponent} />
// After - move `loader`/`Component` to the lazy file
<Route path="/" lazy={() => import('./route') />
// ./route.js
export function loader() { ... }
export function Component() {} |
What's missing from all of these examples (and the docs!) is the default export.
// lazyRoute.js
export function Component(props) { ... }
export function loader() { ... }
// DEFAULT EXPORT OBJECT THAT IS SPREAD ON THE ROUTE!!!
export default { Component, loader }; Edit: I'm mistaken. You just need to have anything but the Component be the default export and it'll work... Default exporting what's spread just makes semantic sense I guess |
I added a small note to the docs to call this out. |
how do you provide a fallback? like a suspense once? |
Hey @brophdawg11 I just exported my component as |
Folks, we really need to stop using this closed issue as a help forum :). Please ask questions in the Discord or open a Q&A Discussion on Github.
There is no difference between |
Sorry to commenting on this after @brophdawg11 asks to close or move, but just to give some workaround. If you use default exports, an easy way to bypass the necessity of {
path: "/pokemons",
lazy: async () => {
const Page = (await import("./pages/pokemons")).default;
return {
element: <Page />,
};
},
} |
@reidark 's answer is the best if you want to still use the default export |
I can solve it this way: const lazyWrap = (factory: () => Promise<any>) => {
return async () => {
const page = await factory()
// https://reactrouter.com/en/main/route/lazy
return {
Component: page.default || page.Component,
ErrorBoundary: page.ErrorBoundary,
loader: page.loader,
}
}
}
const router = createBrowserRouter([
{ path: '/demo', lazy: lazyWrap(() => import('./pages/Demo')) }
]) |
I know the reason. First, your component cannot be export default. Second, if you change the name of your component Home to "Component", there will be no error. I also encountered the same problem. It requires that the name of the lazy component can only be "Component". This is how I solved this problem. |
What version of React Router are you using?
6.9.0
Steps to Reproduce
The docs indicate that the return value of the factory function passed to
lazy
should be aPromise
that resolves with a module that exports one or more of:Component
,ErrorBoundary
,action
, orloader
.There is some type support for this already: the following code will produce a type error:
But if you attempt to load a module that doesn't honor the convention, there is no type error:
Expected Behavior
Ideally the type system would indicate that the
Promise
returned from thelazy
factory must have one or more of the following properties:Component
,ErrorBoundary
,action
,loader
.Beyond type correctness, this would help prevent bugs: it is difficult to imagine a scenario where a consumer would want a route to render nothing and have no behavior.
Actual Behavior
It is currently possible to dynamically import a module that doesn't export one of
Component
,ErrorBoundary
,action
,loader
, and there is no resulting type error.The text was updated successfully, but these errors were encountered: