Antd 3.5.4抽离UserMenu组件时SubMenu创建失败求助
我之前也遇到过Antd 3.x版本中类似的组件抽离问题,本质原因是Antd的Menu组件只会给直接子节点(Menu.Item/SubMenu)注入必要的上下文props,当你把SubMenu包裹在自定义组件里时,这些props无法传递到内部的SubMenu,导致了isRootMenu和onItemHover的错误。
错误原因分析
Antd 3.x的SubMenu依赖父级Menu通过React.Children遍历子元素时注入的一系列核心props:
parentMenu: 指向父级Menu实例,用于判断菜单层级onItemHover: 处理鼠标移入移出的回调函数
当你使用<UserMenu />作为Menu的子组件时,Menu只会把这些props传递给UserMenu本身,而不会自动传递给UserMenu内部的SubMenu,所以SubMenu缺少必要的依赖,抛出错误。
最优解决方案:让UserMenu直接返回Menu子元素
最简单的方法是把UserMenu改成一个返回Menu子元素的纯函数,而不是作为独立组件标签使用,这样返回的SubMenu/Menu.Item会直接成为Menu的子节点,Menu会自动注入所需props。
步骤1:重构UserMenu为纯函数组件
// UserMenu.js import React from 'react'; import { Menu, Avatar } from 'antd'; import { Link } from 'react-router-dom'; const { SubMenu, Item: MenuItem } = Menu; export const UserMenu = ({ user, signOutUser, RoutesNames }) => { if (!user) return null; // 已登录状态:返回SubMenu if (user.isSignedIn) { return ( <SubMenu key="usermenu" title={<Avatar>{user.email.charAt(0).toUpperCase()}</Avatar>} > <MenuItem key="info">{user.email}</MenuItem> <MenuItem key="logout"> <Link onClick={signOutUser}>Log out</Link> </MenuItem> </SubMenu> ); } // 未登录状态:返回登录入口MenuItem return ( <MenuItem key="login"> <Link to={RoutesNames.LOGIN}>Signin / Register</Link> </MenuItem> ); };
步骤2:在父组件中调用函数而非使用组件标签
// 父组件 import { UserMenu } from './UserMenu'; // ... render() { const { currentUser, signOutUser } = this.props; return ( <Menu mode="horizontal"> <Menu.Item key="home"> <Link to={RoutesNames.HOMEPAGE}>Home</Link> </Menu.Item> {/* 直接调用函数,返回的元素会成为Menu的直接子节点 */} {UserMenu({ user: currentUser, signOutUser, RoutesNames })} </Menu> ); }
备选方案:手动传递Menu上下文props(不推荐)
如果你坚持要使用<UserMenu />组件标签的形式,可以通过Menu的ref获取实例,手动把所需props传递给内部的SubMenu,但这种方法需要依赖Antd内部实现,容易在版本更新时出问题:
// 父组件 class ParentComponent extends React.Component { constructor(props) { super(props); this.menuRef = React.createRef(); } render() { const { currentUser, signOutUser } = this.props; return ( <Menu mode="horizontal" ref={this.menuRef}> <Menu.Item key="home"> <Link to={RoutesNames.HOMEPAGE}>Home</Link> </Menu.Item> <UserMenu user={currentUser} signOutUser={signOutUser} RoutesNames={RoutesNames} // 手动传递Menu的核心props parentMenu={this.menuRef.current} onItemHover={this.menuRef.current?.handleItemHover} /> </Menu> ); } }
// UserMenu组件 class UserMenu extends React.Component { render() { const { user, signOutUser, RoutesNames, parentMenu, onItemHover } = this.props; if (user.isSignedIn) { return ( <SubMenu key="usermenu" title={<Avatar>A</Avatar>} parentMenu={parentMenu} onItemHover={onItemHover} > <Menu.Item key="info">{user.email}</Menu.Item> <Menu.Item key="logout"> <Link onClick={signOutUser}>Log out</Link> </Menu.Item> </SubMenu> ); } else { return ( <Menu.Item key="login"> <Link to={RoutesNames.LOGIN}>Signin / Register</Link> </Menu.Item> ); } } }
验证效果
第一种方案实施后,SubMenu会正确获取Menu注入的所有props,鼠标移入移出时的onItemHover错误也会消失,完全恢复之前在同一文件中的正常运行效果。
内容的提问来源于stack exchange,提问作者ARNAUD COSSON -CAMPUS-
相关产品推荐
相关产品推荐

