Mantine polymorphic components with Link
Unanswered
Blood cockle posted this in #help-forum
Blood cockleOP
I've tried out upgrading to Next16 today, and components which follow this pattern:
create an error like this:
I'm used to that error and dealing with it when it makes sense for functions, but LinkComponent is a component.
Has something changed there in how NextJS 16 handles this case?
import Link from 'next/link';
import { ActionIcon } from '@mantine/core';
function Demo() {
return <ActionIcon component={Link} href="/" />;
}create an error like this:
Functions cannot be passed directly to Client Components unless you explicitly expose it by marking it with "use server". Or maybe you meant to call this function rather than return it.
<... component={function LinkComponent} href=... variant=... size=... fullWidth=... h=... p=... styles=... children=...>I'm used to that error and dealing with it when it makes sense for functions, but LinkComponent is a component.
Has something changed there in how NextJS 16 handles this case?
32 Replies
@Blood cockle I've tried out upgrading to Next16 today, and components which follow this pattern:
import Link from 'next/link';
import { ActionIcon } from '@mantine/core';
function Demo() {
return <ActionIcon component={Link} href="/" />;
}
create an error like this:
Functions cannot be passed directly to Client Components unless you explicitly expose it by marking it with "use server". Or maybe you meant to call this function rather than return it.
<... component={function LinkComponent} href=... variant=... size=... fullWidth=... h=... p=... styles=... children=...>
I'm used to that error and dealing with it when it makes sense for functions, but LinkComponent is a component.
Has something changed there in how NextJS 16 handles this case?
no, they made it stricter in terms of type checking and what you can pass to the boundaries. where did you put <Demo/> ?
Blood cockleOP
In a server component at the top of the hierarchy. Basically in the server page controller.
@Blood cockle In a server component at the top of the hierarchy. Basically in the server page controller.
Try adding "use client" in Demo and remove "use client" in Action Icon
Blood cockleOP
Well sure, but that means I can never use a polymorphic component in a server component. Which is awkward for things that are fundamentally just a link. I don't really want to have to wrap each of them in a separate file to make them into a client component at a granular level.
@Blood cockle Well sure, but that means I can never use a polymorphic component in a server component. Which is awkward for things that are fundamentally just a link. I don't really want to have to wrap each of them in a separate file to make them into a client component at a granular level.
>I can never use a polymorphic component in a server component.
you can, just not by passing functions
you can, just not by passing functions
if its "fundamentally" just a link why does it need to be a client component?
just make a "fundamental" component
@Blood cockle Well sure, but that means I can never use a polymorphic component in a server component. Which is awkward for things that are fundamentally just a link. I don't really want to have to wrap each of them in a separate file to make them into a client component at a granular level.
what im asking is to make "Demo" the client boundary not ActionIcon.
let ActionIcon be the polymorphic component but don't let ActionIcon as the client boundary.
this way you only need one "use client" at the top and the rest will be okay as usual
let ActionIcon be the polymorphic component but don't let ActionIcon as the client boundary.
this way you only need one "use client" at the top and the rest will be okay as usual
im not sure how that would lead to "warpping each of them in a separate file to make them into a client component at a granural level"
Thats the thing though, you aren't supposed to make "use client" at a granular level, you aren't supposed to just mark a client-only component with "use client"...
Thats the thing though, you aren't supposed to make "use client" at a granular level, you aren't supposed to just mark a client-only component with "use client"...
"use client" marks as a boundary, as a gate, it does more than converting a component into a client component
architecture-wise you need something that marks as the boundary from server->client.
usually you don't pass function from server to client no?
usually you don't pass function from server to client no?
Blood cockleOP
The pattern that trips me up is something like this:
export async function Page() {
const data = db.select();
return (
<div>
<Paper component={Link} href="/">
{data.title}
</Paper>
</div>
)
}you either have two options:
1.
<Paper type="link" href="/">
2.
<PaperLink href="/">
3.
<Link className="paper" href="/">
or
4.
return <PageUI data={data}> // <-- "use client"
edit:
5.
<Link href="/"><Paper>content</Paper></Link>
1.
<Paper type="link" href="/">
2.
<PaperLink href="/">
3.
<Link className="paper" href="/">
or
4.
return <PageUI data={data}> // <-- "use client"
edit:
5.
<Link href="/"><Paper>content</Paper></Link>
boy im bad at math
Blood cockleOP
There are only two hard problems in computer science:
- concurrency
- naming things
- off-by-one errors
- concurrency
- naming things
- off-by-one errors
haha
number 4 leads you to only making one extra file per route
number 3 leads you to making no extra files
number 2 leads you to making more components for every use cases
number 1 is i think over-engineered and more confusing than the rest
number 3 leads you to making no extra files
number 2 leads you to making more components for every use cases
number 1 is i think over-engineered and more confusing than the rest
so what i usually ended up doing is:
start with 3,
then make it more readable into 2
with combination of 4
start with 3,
then make it more readable into 2
with combination of 4
Blood cockleOP
<Link href="/"><Paper>content</Paper></Link> presumably also works.
sure but that is more line of codes
i will add it to the list
Blood cockleOP
It makes targeting the CSS a bit jankier as well. Which is why I was hoping there was just something I was missing there.
not to mention <Link> creates a BOX model that might ruins styling
yeah i was about to say that
i was having problem with <Form> ruining children styling the other day so i had to refactor styling around the existence of <form>
Blood cockleOP
this may be worth updating with some kind of note - it worked in 15 but now doesn't in 16.
I think it shouldn't work in 15 either. like the latest verison of 15
this code
Blood cockleOP
I'm on "next": "^15.5.6" and it seems to work. But if I upgrade to 16 it breaks.
interesting
i have confirmed your observation
Blood cockleOP
🤷♂️ That's what tripped me up in the first place. It made sense that it worked, and it also makes sense that it shouldn't work from a deeper technical level, but it makes less sense that it switched from working to not working.