Functions cannot be passed directly to Client Components unless you explicitly expose it by marking
Unanswered
Ruffed Grouse posted this in #help-forum
Ruffed GrouseOP
Hello, i have these files
Page.tsx
const createAlertAction = (message: string) => {
return () => alert(message)
}
const Dashboard: NextPage = async () => {
const user = await UserAPI.getData()
return (
<div className="grid w-full grid-cols-12 gap-6">
<div className="col-span-9 w-full space-y-6">
<Banner
{...{
header:
description:
"Explore the diverse paths and tools available on MyIP.",
ctx: [
{
variant: "outline",
className: "bg-ip-main",
text: "Shop Courses",
action: createAlertAction("hi"),
},
{
className: "border-white",
variant: "outline",
text: "View Active Courses",
action: createAlertAction("hi"),
},
],
}}
/>
<AppLauncher
{...{
apps: [
{
backgroundImage: {
src: BgAcademAppCard,
},
icon: { src: AcademyIcon },
headerText: "Academy",
description: "Upskill Your IT Knowledge.",
ctx: {
text: "Launch",
action: createAlertAction("hi"),
},
},
To my component
import React from "react"
import Image from "next/image"
import BusinessManImage from "@/assets/png/business-man.png"
import BusinessWomanImage from "@/assets/png/business-woman.png"
import DashboardBannerImage from "@/assets/png/main-bg-shapes.png"
import { IPButton, IPTypography, Tag } from "@/ui/common"
export interface BannerProps {
header: string
description: string
ctx: {
className?: string
variant?: "outline"
text: string
action: () => void
}[]
}
const Banner: React.FC<BannerProps> = ({ header, description, ctx }) => {
return (
<div className="space-y-4">
<IPTypography className="text-5xl font-bold tracking-tighter">
{header}
</IPTypography>
<IPTypography className="text-lg text-muted-foreground" tag={Tag.P}>
{description}
</IPTypography>
<div className="space-x-4">
{ctx.map((btn, idx: number) => (
<IPButton
key={idx}
className={btn.className}
variant={btn.variant}
onClick={btn.action}
text={btn.text}
/>
))}
</div>
</div>
)
}
export { Banner }
But i keep getting this error Error: Functions cannot be passed directly to Client Components unless you explicitly expose it by marking it with "use server".
I want my page.tsx to be a server component as it will be getting data, but i want to specify the client side action for each btn. How do i do so?
Page.tsx
const createAlertAction = (message: string) => {
return () => alert(message)
}
const Dashboard: NextPage = async () => {
const user = await UserAPI.getData()
return (
<div className="grid w-full grid-cols-12 gap-6">
<div className="col-span-9 w-full space-y-6">
<Banner
{...{
header:
Welcome Back ${user.firstName}
,description:
"Explore the diverse paths and tools available on MyIP.",
ctx: [
{
variant: "outline",
className: "bg-ip-main",
text: "Shop Courses",
action: createAlertAction("hi"),
},
{
className: "border-white",
variant: "outline",
text: "View Active Courses",
action: createAlertAction("hi"),
},
],
}}
/>
<AppLauncher
{...{
apps: [
{
backgroundImage: {
src: BgAcademAppCard,
},
icon: { src: AcademyIcon },
headerText: "Academy",
description: "Upskill Your IT Knowledge.",
ctx: {
text: "Launch",
action: createAlertAction("hi"),
},
},
To my component
import React from "react"
import Image from "next/image"
import BusinessManImage from "@/assets/png/business-man.png"
import BusinessWomanImage from "@/assets/png/business-woman.png"
import DashboardBannerImage from "@/assets/png/main-bg-shapes.png"
import { IPButton, IPTypography, Tag } from "@/ui/common"
export interface BannerProps {
header: string
description: string
ctx: {
className?: string
variant?: "outline"
text: string
action: () => void
}[]
}
const Banner: React.FC<BannerProps> = ({ header, description, ctx }) => {
return (
<div className="space-y-4">
<IPTypography className="text-5xl font-bold tracking-tighter">
{header}
</IPTypography>
<IPTypography className="text-lg text-muted-foreground" tag={Tag.P}>
{description}
</IPTypography>
<div className="space-x-4">
{ctx.map((btn, idx: number) => (
<IPButton
key={idx}
className={btn.className}
variant={btn.variant}
onClick={btn.action}
text={btn.text}
/>
))}
</div>
</div>
)
}
export { Banner }
But i keep getting this error Error: Functions cannot be passed directly to Client Components unless you explicitly expose it by marking it with "use server".
I want my page.tsx to be a server component as it will be getting data, but i want to specify the client side action for each btn. How do i do so?
1 Reply
Ruffed GrouseOP
1) i have my layout/navbar/user (server component) which will then fetch /@me in the server, then i also have a AuthProvider (server component) that also fetches @me. then i have the settings profile page (Server Component) that also fetches @me. Is that good practice in the new app router, as requests will automatically be deduplicated?
2) does anyone have a full stack application example of fetching apis using the new next/app router
3) I have my page.tsx (server) which passes the data needed to my client components, how am i supposed to send the client action (redirect, open modal, etc) to that
const createAlertAction = (message: string) => {
return () => alert(message)
}
const Dashboard: NextPage = async () => {
const user = await UserAPI.getData()
return (
<div className="grid w-full grid-cols-12 gap-6">
<div className="col-span-9 w-full space-y-6">
<Banner
{...{
header:
description:
"Explore the diverse paths and tools available on MyIP.",
ctx: [
{
variant: "outline",
className: "bg-ip-main",
text: "Shop Courses",
// action: createAlertAction("hi"),
},
{
className: "border-white",
variant: "outline",
text: "View Active Courses",
// action: createAlertAction("hi"),
},
],
}}
/>
export interface BannerProps {
header: string
description: string
ctx: {
className?: string
variant?: "outline"
text: string
action: () => void
}[]
}
const Banner: React.FC<BannerProps> = ({ header, description, ctx }) => {
return (
<div className="space-y-4">
<IPTypography className="text-5xl font-bold tracking-tighter">
{header}
</IPTypography>
<IPTypography className="text-lg text-muted-foreground" tag={Tag.P}>
{description}
</IPTypography>
<div className="space-x-4">
{ctx.map((btn, idx: number) => (
<IPButton
key={idx}
className={btn.className}
variant={btn.variant}
onClick={btn.action}
text={btn.text}
/>
))}
</div>
</div>
)
}
2) does anyone have a full stack application example of fetching apis using the new next/app router
3) I have my page.tsx (server) which passes the data needed to my client components, how am i supposed to send the client action (redirect, open modal, etc) to that
const createAlertAction = (message: string) => {
return () => alert(message)
}
const Dashboard: NextPage = async () => {
const user = await UserAPI.getData()
return (
<div className="grid w-full grid-cols-12 gap-6">
<div className="col-span-9 w-full space-y-6">
<Banner
{...{
header:
Welcome Back ${user.firstName}
,description:
"Explore the diverse paths and tools available on MyIP.",
ctx: [
{
variant: "outline",
className: "bg-ip-main",
text: "Shop Courses",
// action: createAlertAction("hi"),
},
{
className: "border-white",
variant: "outline",
text: "View Active Courses",
// action: createAlertAction("hi"),
},
],
}}
/>
export interface BannerProps {
header: string
description: string
ctx: {
className?: string
variant?: "outline"
text: string
action: () => void
}[]
}
const Banner: React.FC<BannerProps> = ({ header, description, ctx }) => {
return (
<div className="space-y-4">
<IPTypography className="text-5xl font-bold tracking-tighter">
{header}
</IPTypography>
<IPTypography className="text-lg text-muted-foreground" tag={Tag.P}>
{description}
</IPTypography>
<div className="space-x-4">
{ctx.map((btn, idx: number) => (
<IPButton
key={idx}
className={btn.className}
variant={btn.variant}
onClick={btn.action}
text={btn.text}
/>
))}
</div>
</div>
)
}