当前位置: 首页 > 知识库问答 >
问题:

前端 - 请问为何antd/dropdown的menu属性传递调用函数生成items会报错呢?

严景焕
2023-09-24

我有如下的代码使用antd/Dropdown组件:

image.png

 const items: MenuProps["items"] = [    {      label: <div  onClick={() => {        console.log('收藏: ')      }}>收藏</div>,      key: '0',    },    {      label: <a>2nd menu item</a>,      key: '1',    },    {      type: 'divider',    },    {      label: '3rd menu item',      key: '3',    },  ];... <Dropdown     key={nodeData.key}     menu={{ items }}     trigger={['click']}     open={isOpenObj[nodeData.key]}    onOpenChange={()=>{      updateIsOpenObj(nodeData.key, false)    }}    >      <a onClick={(e) => {        e.preventDefault()      }}>        <Space>        </Space>      </a>    </Dropdown>

这样使用是没有问题的:
调用打开dropdown:
image.png

但是我修改为此代码(使用genDropdownItems()生成items,而不直接传递items,就会报错):

// 生成dropdown的key  const genDropdownItems = (key: string | number): MenuProps["items"]  => {    const items: MenuProps["items"] = [      {        label: <div  onClick={() => {          console.log('收藏: ', key)        }}>收藏</div>,        key: '0',      },      {        label: <a>2nd menu item</a>,        key: '1',      },      {        type: 'divider',      },      {        label: '3rd menu item',        key: '3',      },    ];    return items   }<Dropdown     key={nodeData.key}     //menu={{ items }}     menu={genDropdownItems(nodeData.key)}    trigger={['click']}     open={isOpenObj[nodeData.key]}    onOpenChange={()=>{      updateIsOpenObj(nodeData.key, false)    }}    >      <a onClick={(e) => {        e.preventDefault()      }}>        <Space>        </Space>      </a>    </Dropdown>

报错结果:
image.png

Unhandled Runtime ErrorError: React.Children.only expected to receive a single React element child.Call StackObject.onlyChild [as only]...at PathnameContextProviderAdapter (webpack-internal:///../node_modules/.pnpm/registry.npmmirror.com+next@13.5.2_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/shared/lib/router/adapters.js:79:11)    at ErrorBoundary (webpack-internal:///../node_modules/.pnpm/registry.npmmirror.com+next@13.5.2_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/compiled/@next/react-dev-overlay/dist/client.js:2:5389)    at ReactDevOverlay (webpack-internal:///../node_modules/.pnpm/registry.npmmirror.com+next@13.5.2_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/compiled/@next/react-dev-overlay/dist/client.js:2:7785)    at Container (webpack-internal:///../node_modules/.pnpm/registry.npmmirror.com+next@13.5.2_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/index.js:78:1)    at AppContainer (webpack-internal:///../node_modules/.pnpm/registry.npmmirror.com+next@13.5.2_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/index.js:182:11)    at Root (webpack-internal:///../node_modules/.pnpm/registry.npmmirror.com+next@13.5.2_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/index.js:396:11)React will try to recreate this component tree from scratch using the error boundary you provided, ErrorBoundary.

共有3个答案

许曦
2023-09-24

函数调用不是这样写的么 menu={()=>genDropdownItems(nodeData.key)}

马博学
2023-09-24

你少了对{}吧

const genDropdownItems = (key: string | number): MenuProps["items"]  => {    const items: MenuProps["items"] = [      {        label: <div  onClick={() => {          console.log('收藏: ', key)        }}>收藏</div>,        key: '0',      },      {        label: <a>2nd menu item</a>,        key: '1',      },      {        type: 'divider',      },      {        label: '3rd menu item',        key: '3',      },    ];    //return items    return { items }   }
华烈
2023-09-24

看起来你的问题是在尝试将函数genDropdownItems()作为menu属性值传入Dropdown组件时遇到了错误。从React的角度来看,这个错误可能是因为genDropdownItems()函数没有返回一个有效的React元素。

在Next.js和React中,一个组件只能有一个子元素,这是由React的React.Children.only()函数保证的。这个函数期望只有一个子元素,如果有多于一个的子元素,它就会抛出错误。在你的代码中,genDropdownItems()函数返回了一个数组,而这个数组被作为menu属性的值传递给了Dropdown组件,这就导致了错误的发生。

解决这个问题的一种方式是修改genDropdownItems()函数,让它返回一个有效的React元素,而不是一个数组。例如,你可以将每个菜单项封装在一个<MenuItem />组件中,并返回一个包含所有这些<MenuItem />组件的数组。

下面是一个可能的解决方案:

const MenuItem = ({ label, onClick }) => (  <div onClick={onClick}>    {label}  </div>);const genDropdownItems = (key: string | number): MenuProps["items"] => {  const items: MenuProps["items"] = [    {      label: <MenuItem onClick={() => { console.log('收藏: ', key); }}>收藏</MenuItem>,      key: '0',    },    {      label: <MenuItem>2nd menu item</MenuItem>,      key: '1',    },    {      type: 'divider',    },    {      label: '3rd menu item',      key: '3',    },  ];  return items; }//...你的其他代码...<Dropdown     key={nodeData.key}     menu={genDropdownItems(nodeData.key)}    trigger={['click']}     open={isOpenObj[nodeData.key]}    onOpenChange={()=>{      updateIsOpenObj(nodeData.key, false)    }}    >      <a onClick={(e) => {        e.preventDefault()      }}>        <Space>        </Space>      </a>    </Dropdown>

在这个解决方案中,我们创建了一个新的MenuItem组件来封装每个菜单项的显示和点击行为,然后在genDropdownItems()函数中返回包含这些MenuItem组件的数组。这样,Dropdown组件就可以正确地接收并渲染这些菜单项了。

 类似资料:
  • Overview Quick setup Plugin configuration Overview This plugin allows adding a configurable dropdown menu to the table's column headers. The dropdown menu acts like the Context Menu, but is triggered

  • 描述 (Description) 下拉菜单插件用于在主菜单下创建子菜单。 data-dropdown-menu属性有助于将嵌套菜单转换为下拉菜单列表。 下表描述了不同类型的下拉菜单以及说明。 Sr.No. 功能和描述 1 Horizontal 通过将属性data-dropdown-menu和类下拉列表包含在菜单容器中来设置下拉列表。 2 Vertical 通过将类垂直包含在顶级菜单中,可以垂直显示

  • 描述 (Description) 下拉菜单用于以列表格式显示链接。 例子 (Example) 以下示例演示了在Foundation中使用dropdown menu - <!doctype html> <head> <meta charset = "utf-8" /> <meta http-equiv = "x-ua-compatible" content = "ie

  • 新手Gatling Scala问题:我正在使用George Leung的gatling-grpc库(它以超文本传输协议库为模型)并尝试将会话中的值(在进纸器中生成)传递到非DSL、非Gatling方法调用中,特别是调用填充gRPC有效负载对象。 在开始之前,让我补充一点,我似乎无法使用的sessionFunction()形式来解决我的问题: …因为,AFAICT,调用必须是块中的最后一个内容,否则

  • Use Cases Create a shortcut for an action or a series of actions that the user repeatedly does. Create a button for custom behavior. How to create custom menu items The methods for adding custom menu

  • 需求是这样的 已选中的数据现在放一个数组里,数组里的时间也转换成了字符串,但是报这个错