You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js 14.0.3:服务端传图标到客户端组件报错求解决

问题描述

使用Next.js 14.0.3时,将Lucide图标从服务端组件传递到客户端组件时,出现错误:

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

服务端组件代码(SidebarRoutes.tsx):

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;

客户端组件代码(SidebarItem.tsx):

'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;

由于需要使用usePathname做条件渲染,SidebarItem必须是客户端组件,求修复方法。

修复方法

方法1:传递图标名称,客户端动态映射组件

修改服务端组件传递图标名称字符串,客户端通过映射表匹配对应图标组件:

服务端组件(SidebarRoutes.tsx)修改:

import React from "react";
import SidebarItem from "./SidebarItem";

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

function SidebarRoutes() {
  const routes = guestRoutes;

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

export default SidebarRoutes;

客户端组件(SidebarItem.tsx)修改:

'use client';

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

// 建立图标名称与组件的映射关系
const iconMap: Record<string, LucideIcon> = {
  Layout,
  Compass,
};

interface SidebarItemProps {
  label: string;
  path: string;
  iconName: keyof typeof iconMap;
}

const SidebarItem = ({ label, iconName, path }: SidebarItemProps) => {
  const router = useRouter();
  const pathname = usePathname();
  const Icon = iconMap[iconName];

  return (
    <Icon />
  );
};

export default SidebarItem;

方法2:服务端预渲染图标JSX,传递渲染结果

直接在服务端组件中渲染图标,将已生成的JSX传递给客户端组件:

服务端组件(SidebarRoutes.tsx)修改:

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;

客户端组件(SidebarItem.tsx)修改:

'use client';

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

interface SidebarItemProps {
  label: string;
  path: string;
  icon: React.ReactNode;
}

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

  return (
    <>{icon}</>
  );
};

export default SidebarItem;

方法3:创建服务端图标包装组件

通过服务端组件包装图标,再将包装后的JSX传递给客户端:

创建IconWrapper.tsx(服务端组件):

import React from "react";
import { LucideIcon } from "lucide-react";

interface IconWrapperProps {
  icon: LucideIcon;
  props?: React.ComponentProps<LucideIcon>;
}

export default function IconWrapper({ icon: Icon, props }: IconWrapperProps) {
  return <Icon {...props} />;
}

服务端组件(SidebarRoutes.tsx)修改:

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

const guestRoutes = [
  {
    label: "Home",
    path: "/",
    icon: <IconWrapper icon={Layout} />,
  },
  {
    label: "Browse",
    path: "/search",
    icon: <IconWrapper 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;

客户端组件(SidebarItem.tsx)同方法2的修改即可

内容的提问来源于stack exchange,提问作者user22741641

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 07:34:55