next.jsnext.js14

Functions cannot be passed directly to Client Components


I am using next js 14.0.3, when i passed the icon from server component to client componet its gives my this error

'Functions cannot be passed directly to Client Components unless you explicitly expose it by marking it with "use server".'

this is server component

import React from "react";
import { Layout, Compass } from "lucide-react";
import SidebarItem from "./SidebarItem";

const guestRoutes = [
  {
    label: "Home",
    path: "/",
    icon: Layout,
  },
  {
    label: "Browse",
    path: "/search",
    icon: Compass,
  },
];

function SidebarRoutes() {
  const routes = guestRoutes;

  return (
    <div className="flex mt-4 flex-col h-full">
      {routes.map((route) => {
        return (
          <SidebarItem
            key={route.path}
            icon={route.icon}
            label={route.label}
            path={route.path}
          />
        );
      })}
    </div>
  );
}

export default SidebarRoutes;

and this is clinet component

'use client';

import React from "react";
import { LucideIcon } from "lucide-react";
import { usePathname, useRouter } from "next/navigation";

interface SidebarItemProps {
  label: string;
  path: string;
  icon: LucideIcon;
}
const SidebarItem = ({ label, icon: Icon, path }: SidebarItemProps) => {
  const router = useRouter();
  const pathname = usePathname();

  return (
    <Icon/>
  );
};

export default SidebarItem;

anyone know how can i fix it

I have to check the path name for conidional rendering thats why i need to convert this component into client side, I tried but not fixing


Solution

  • I had the same issue, and I fixed it. The solution is:

    Your icon must be a string, like this:

    const guestRoutes = [
        {
            label: "Home",
            path: "/",
            icon: "Layout",
        },
        {
            label: "Browse",
            path: "/search",
            icon: "Compass",
        },
    ];
    

    Then, you must be create a new component like this:

    import * as LuIcon from 'lucide-react';
    
    interface IconCheckProps{
        icon: string;
    }
    
    const IconCheck = ({ icon }: IconCheckProps) => {
        const IconLibraries = { ...LuIcon };
        const IconComponent = IconLibraries[icon as keyof typeof IconLibraries];
    
        if (!IconComponent) {
            return null;
        }
    
        return <IconComponent />;
    }
    

    Which you can call like that:

    interface SidebarItemProps{
        label: string;
        path: string;
        icon: string;
    }
    
    const SidebarItem = ({ label, icon, path }: SidebarItemProps) => {
        const router = useRouter();
        const pathname = usePathname();
    
        return (
            <IconCheck icon={icon}/>
        );
    }