-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Description
I have some react wrappers which i have generated from my lit components. These work great in a pure client-side react app. However when using in a next.js app i hit a number of a problems.
Elliot on slack asked me to raise an issue here. Even though i think some of it is an issue on the next.js side, it might help in tracking your next integration story.
Steps to Reproduce
- Write this code
import React from "react";
import dynamic from "next/dynamic";
// @org/react contains lit-labs/react wrappers...
// (1) ts error
const MyInput = dynamic(() => import("@org/react").then(({ Input }) => Input), {
ssr: false,
});
export const Page = () => {
const ref = React.useRef();
// (2) ref issue
const focusInput = () => ref.current.focus();
return (
<>
<MyInput ref={ref} />
<button onClick={focusInput}>Click me</button>
</>
);
};- See this output...
(1) TS complains about the type of the react wrapper component. To fix this I had to cast to any and then back to my actual type. I created a helper function like:
type ComponentModule = typeof import("@org/react");
function createDynamic<
K extends keyof ComponentsModule,
T extends ComponentsModule[K]
>(component: K) {
return dynamic(
() => import("@org/react").then((module) => module[component] as any),
{ ssr: false }
) as T;
}
const MyInput = createDynamic("Input");(2) when clicking the button you will get an error because the ref is not pointing to the underlying custom-element as you would expect, but rather (i think) the return type of dynamic.
I was able to work around this by adding some indirection and threading through a ref myself:
type ComponentsModule = typeof import("@org/react")
function createDynamic<
K extends keyof ComponentsModule,
T extends ComponentsModule[K]
>(component: K) {
const Wrapped = dynamic(
() =>
import("@org/react").then(module => {
const Component = module[component] as any
// @ts-expect-error innerRef is unknown
const Wrapped = ({ innerRef, ...props }) => <Component ref={innerRef} {...props} />
Wrapped.displayName = `Wrapped${component}`
return Wrapped as any
}),
{ ssr: false }
)
// @ts-expect-error innerRef is unknown
const Forwarded = React.forwardRef((props, ref) => <Wrapped {...props} innerRef={ref} />)
Forwarded.displayName = `Forwarded${component}`
return Forwarded as T
}
const MyInput = createDynamic("Input")This is of course, horrible. I tried various other combinations of forwardRef and/or custom ref properties, but i coudln't get it to work. I even had to suppress some TS issues.
This got so complex, i had to add next.js specific integration to my react package as it would be very difficult to document these issues in such a way that devs consuming the components would understand. It was easier to just give them something they can import for next.js only
Expected Results
(1) no TS errors
(2) refs should work out of the box
Metadata
Metadata
Assignees
Labels
Type
Projects
Status