Ant-design: 不能与HOC一起使用的`antd`组件列表

创建于 2017-02-14  ·  65评论  ·  资料来源: ant-design/ant-design

这不是常见的用例,因此优先级较低。 但是我们仍然可以讨论并尝试使其变得更好:

Inactive ❓FAQ 🗣 Discussion

最有用的评论

这个问题应该在文档中真正提到,我浪费了一个完整的工作日来研究这个错误,只是为了了解这个库对我来说是不可用的。 请发出警告,这样其他开发人员就不必浪费太多时间弄清楚您使用的是反模式,中继React密钥,而现在您对于社区中可用的许多HOC或装饰器非常脆弱。
真是可惜。 希望您可以在下一个主要版本中对其进行修复。

所有65条评论

这很困难,因为某些组件将key作为API的一部分,在重命名所有API名称之前,我们无法修复此问题。 例如

key => id
expandedKeys => expandedIds
selectedKeys => selectedIds
....

这将是一个重大更改,但是这种重大更改可以通过antd-codemod解决。

所以,您认为这样做值得吗?

我认为这不是一个好主意。

不喜欢codemod解决方案。
只是我的观点,但是,我相信对于大多数人来说,它令人反感而不是受欢迎。

将组件嵌入自定义组件是React的一种常见做法。

请对其进行修复,毫无疑问,蚂蚁设计的采用会迅速增加。

Ant Design确实很吸引人,并且是第一个使我想离开react-bootstrap的库。

@麦肯图

很难,因为某些组件将密钥用作API的一部分,只有在重命名所有API名称之前,我们才能解决此问题。

@ afc163如果无法重命名这些API,则无法解决此问题。 但是我们可以提供解决方法,请参阅: https :

您认为我们应该将此添加到文档中吗?

@benjycui我了解。

无论如何,它毕竟不是阻塞。

感谢您抽出宝贵的时间回答。

@benjycui我正在调查您提出的解决方法,但我认为这不是一个适当的解决方案。 通常,在包装组件时,您还希望具有一些内部状态。 对于提出的解决方案,这是不可能的。
我也认为这不是一个小问题。 无法隔离公共组件意味着在应用程序内部多次重复相同的代码。 如果应用程序很大,我会考虑根本不采用antd。 请将此视为建设性的批评家。
感谢您的工作!

同意说这不是一个小问题,这是我开始使用Ant Design库时没想到的事情,自定义组件的良好做法在整个React项目中得到了使用。 就个人而言,我真的很喜欢Ant Design,但对于某些人来说,这可能是一个大问题。 真希望看到即将推出的Ant Design v3对此功能进行改进。

请在v3中找到解决方案。

软件包发布后可以解决(也许)。

只是遇到了这种尝试(很抱歉,如果这是错误的),使用菜单创建导航栏并在菜单中嵌套<Link />标签与<Icon />嵌套。

有更优选的解决方案吗?

恕我直言,该线程应该在官方文档中,因为对于许多用户来说,此问题可能是一个大问题。
当不需要状态时,文档还应提及https://github.com/react-component/collapse/issues/73#issuecomment -323626120。

我肯定会在文档中提及此内容! 我试图做这样的事情,浪费了很多时间,因为它不起作用。

<Collapse>
   <MyCollapseItem />
   <MyCollapseItem2 />
</Collapse>

其中MyCollapseItemMyCollapseItem2呈现Collapse.Panel

而且,由于react16允许您从渲染返回组件数组,因此能够特别有用。 否则,防止重复代码具有挑战性。

有任何更新吗?

这实际上是我们的主要问题。 我投票支持重命名重大更改,因为我无法想到任何解决方法。

同样在这里-我需要Tabs.TabPaneMenu.MenuItem

我发现一种解决方法基本上可以通过传递其余的道具从包装的组件。

如果您与React.Children.map(children, (child, index) => { ... })则无法解决该问题,至少对我而言。 最后,键属性得到一个像mykey/.0这样的值,这不是我可以工作的。 我也投票赞成对属性进行名称更改。

这个问题实际上可能使我远离antd ...或至少使我找到了这些组件的替代品。 它确实限制了您创建可重用组件的能力。

对于尝试在Menu.Item中使用React Router的任何人,@ yunshuipiao都有一个成功的解决方案,在#6576中为我工作

另一个小问题:包装Menu.Item还会阻止在子菜单之一被选中时(至少在垂直模式下)子菜单出现。 相关行:

https://github.com/react-component/menu/blob/018d6f84d622ee140d9695ba57e7a773cf368efa/src/util.js#L40
https://github.com/react-component/menu/blob/018d6f84d622ee140d9695ba57e7a773cf368efa/src/SubMenu.jsx#L314

我想为那些试图使Collapse与自定义组件一起工作的人提供文档:与@jfreixa提到的类似,只需将提供给自定义组件的所有道具传递给面板,例如

<Collapse>
  <Custom/>
  <Custom/>
</Collapse>


Custom.render() {
  return (
    <Panel {...this.props}>
      <div>My custom stuff here</div>
    </Panel>
  )
}

与@ncknuna相同。

包装时不选择Menu.Item。 有解决方法吗?

@Nomeyho我最终通过复制/粘贴相关方法并注释掉原始检查,然后在我的包装器中将类作为className传递,来确定确定是否添加ant-menu-submenu-selected类的逻辑:

function loopMenuItemRecusively (children: Array<any>, keys: Array<string>, ret: { find: boolean }) {
  if (!children || ret.find) {
    return
  }
  React.Children.forEach(children, (c: any) => {
    if (ret.find) {
      return
    }
    if (c) {
      const construt = c.type
      // Original check that caused problems. I'm not concerned about omitting it
      // because I don't plan on putting a bunch of weird, large stuff in my menus...
      // if (!construt || !(construt.isSubMenu || construt.isMenuItem || construt.isMenuItemGroup)) {
      //   return;
      // }
      if (keys.indexOf(c.key) !== -1) {
        ret.find = true
      } else if (c.props && c.props.children) {
        loopMenuItemRecusively(c.props.children, keys, ret)
      }
    }
  })
}

function isChildrenSelected (children: Array<any>, selectedKeys: Array<string>) {
  const ret = { find: false }
  loopMenuItemRecusively(children, selectedKeys, ret)
  return ret.find
}

// Omitting other custom code below...
export const SubMenu = ({ children, className, selectedKeys, title, ...rest }: any) => {
  const isSelected = isChildrenSelected(children, selectedKeys)
  className = [
    className,
    isSelected ? 'ant-menu-submenu-selected' : ''
  ].filter(className => classname).join(' ')
  return (
    <SubMenu title={title} className={className} selectedKeys={selectedKeys} {...rest}>
      {children}
    </SubMenu>
  )
}

有没有解决办法?

我同意@ChuckJonas

这个问题实际上可能使我远离antd ...或至少使我找到了这些组件的替代品。 它确实限制了您创建可重用组件的能力。

我需要像这样使用Menu SubMenu和Menu.items:
为什么? 因为我可以在其他页面中使用“ CustomSubMenu”元素,所以这是“可重用”组件的重要组成部分。

_MainFile.js_

Import CustomSubMenu from './OtherFile.js';

<Menu>
    <CustomSubMenu />
    <CustomSubMenu2 />
    <CustomSubMenu3 />
</Menu>

和OtherFile.js像这样:

render(){
 return(
     <SubMenu>
           <SubMenu.item />
           <SubMenu.item2 />
            etc...etc...
     </SubMenu>
 );
}

子菜单的临时解决方法(为简化起见进行了编辑):

const SubMenuArray = ({ ...props }) =>
  [1, 2].map(i => (
    <Menu.SubMenu {...props} eventKey={`item_${i}`} subMenuKey={`${i}-menu-`} />
  ));

处理数组时:

  • 传递道具
  • 添加eventKeysubMenuKey ,这应该是唯一的

更好的方法可能是:

const SubMenuWrapper = ({ children, ...props }) =>
  React.Children.map(children, (child, i) =>
    React.cloneElement(child, {
      ...props,
      eventKey: `item_${i}`,
      subMenuKey: `${i}-menu-`
    })
  );

用法:

      <Menu>
        <SubMenuWrapper>
          <CustomSubMenu title={"one"}/>
          <CustomSubMenu title={"two"}/>
        </SubMenuWrapper>
      </Menu>

同样,您可能不想在数组中使用索引,因此不要在生产中使用该索引,但是这个想法很可靠。

  • 1可以将antd组件嵌入到自定义组件中。 这对我们来说是成败

我认为我们有一种消除键依赖的方法。 以Menu为例,我们可以引入一个itemKey道具,然后使用context来实现Menu。 为了保持兼容性,菜单仍会遍历子级,并将key更改itemKey如果显示)。 同时,我们还可以保留道具的语义,例如selectedKeys

@yesmeck说实话,由于我不使用ant design但计划在本周内将其用于重要的应用程序),ant design一段时间

据我了解,您可以从应对新context API作为变通办法中受益?

那是个好消息

是的,我们需要context而不是cloneElement来解决问题。

我认为解决方案是不使用“ React.Children.forEach”和“ React.cloneElement”来传递道具和设置新道具,而是使用一个函数,例如自定义:

<Select>
  {({ onSelect }) => (
    <div>
      <Option onClick={onSelect} key="0">option1</Option>
      <Option onClick={onSelect} key="1">option2</Option>
    </div>
  )
</Select>

并且antd select源还使用了功能子项props,而不是“ React.Children.forEach”和“ React.cloneElement”

如果这是一个愚蠢的问题,请原谅,但是我对React和Ant Design还是很陌生。
这是否意味着实际上我们不能在react-redux连接的SPA中使用Ant设计菜单?
如果是这样,如何使用Ant Design编写相对复杂的SPA? 有解决方法吗?

这事有进一步更新吗?

关于此问题有任何更新吗? 菜单项与HOC异常。

嗨! 同样在这里,我对能够自定义此类组件非常感兴趣。
自定义Select.Option确实有问题

此线程中没有提出任何解决方法帮助我使其正常工作,我有一个有效的选择,其中有空选项...。

import React from 'react';
import PropTypes from 'prop-types';
import { Select } from 'antd';

const { Option } = Select;

const PictureOption = ({ label, value, pictureId, ...props }) => (
    <Option label={label} value={value} className="select-item" {...props}>
        <div className="select-item__thumbnail">
            <img src={pictureId} alt="item-img" />
        </div>
        <div className="select-item__name">{label}</div>
    </Option>
);

PictureOption.propTypes = {
    label: PropTypes.string.isRequired,
    value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
    pictureId: PropTypes.string.isRequired,
};

export default PictureOption;

我开始使用CASL根据用户权限呈现UI元素。 但是,我遇到了一个问题,即子菜单未呈现,因为对props未正确传播到子元素的事实,对isRootMenu函数的调用失败。

作为解决方法,我将SubMenus定义为常量,并“手动”传递了props:
``
render(){

// ### Administration Menu ###
const AdminMenu = ({ ...props }) => {
  return (
    <Can I="access" on="admin-content">
      <Menu.Divider {...props} />
      <Menu.SubMenu
        {...props}
        title={
          // FIXME: Icon is not rendered... :-/
          <span>
            <Icon type="tools" />
            <span>Administration</span>
          </span>
        }
        // title={<span>Administration</span>}
        key="admin">
        <Menu.Item key="users" tabIndex={0}>
          <Icon type="android" />
          <span>User Administration</span>
        </Menu.Item>
        <Menu.Item key="permissions" tabIndex={0}>
          <Icon type="lock" />
          <span>Permissions</span>
        </Menu.Item>
      </Menu.SubMenu>
    </Can>
  );
};

return (
  <Layout id="menu-component-layout">
    <Layout.Sider width="300px" collapsible="false" trigger={null}>
      <Menu theme="dark" mode="inline" defaultSelectedKeys={['user']} defaultOpenKeys={['user', 'config', 'admin']}>
        <AdminMenu />
      </Menu>
    </Layout.Sider>
    <Layout.Content id="menu-component-content">
      <h3>Page containing a side menu</h3>
    </Layout.Content>
  </Layout>
);

}
``

该解决方案不是很方便,但目前可以使用。 但是,我仍然有一个问题,即包含图标的子菜单的标题未正确呈现。 该图标丢失。

有谁知道如何解决这个问题?

我在这里创建了一个展示柜: https :

的GitHub
使用ant-design UI库在流星/反应环境中展示CASL授权库的用法-gibelium / meteor-react-antd-casl

@gibelium我认为图标渲染实际上应该解决它自己的问题。 我克隆了您的仓库,并尝试用重影按钮替换图标,并且按钮轮廓可见,但是图标也无法在按钮中/在按钮上呈现...

@gotjoshua您将创建那个专门的问题吗?

设置默认的扩展菜单项也不起作用。 我的解决方法实现忽略Menu的defaultOpenKeys属性。

任何想法如何解决?

这个问题应该在文档中真正提到,我浪费了一个完整的工作日来研究这个错误,只是为了了解这个库对我来说是不可用的。 请发出警告,这样其他开发人员就不必浪费太多时间弄清楚您使用的是反模式,中继React密钥,而现在您对于社区中可用的许多HOC或装饰器非常脆弱。
真是可惜。 希望您可以在下一个主要版本中对其进行修复。

关于此问题有任何更新吗? 设置菜单defaultOpenKeys不起作用

总的来说,应该很快就将其视为高度优先事项。 🔥

我有(可能)无法实现的类似用例。
我想创建Redux连接的组件,该组件使用基于Redux存储中数据的选项来渲染Select 。 由于我不想在各处“复制粘贴”相同的代码,因此我想在Form.getFieldDecorator使用这种类型的组件,但是由于使用了connect HOC,所以我无法执行此操作它。

编辑:我找到了我的用例的解决方案。 我可以使用forwardRef选项创建上述组件,如下所示:
connect(mapStateToProps, mapDispatchToProps, null, { forwardRef: true })(Component);
此解决方案特定于connect HOC,但是您应该能够使用React.forwardRef创建类似的解决方案。

除了先前的评论外,是的,我也认为这可以被视为高度优先。 在我成功解决了一个问题(如上所述)之后,现在需要创建用自定义组件包装的Tabs.TabPane组件。 我有一个非常常见的用例->包装组件用于检查权限,因此如果满足条件,则呈现子组件,否则不提供。

有没有简单可行的解决方法?

请对此进行任何更新?

我发现一种解决方法基本上可以通过传递其余的道具从包装的组件。

这显示了控制台警告。有什么办法可以解决此问题?
index.js:1437 Warning: React does not recognize the staticContext prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase staticcontext`。 如果您不小心从父组件传递了它,请将其从DOM元素中删除。

index.js:1437警告:道具dispatch值无效

  • 标签。 从元素中删除它,或传递一个字符串或数字值以将其保留在DOM中。 有关详细信息,请参见https://fb.me/react-attribute-behavior
    in li(由MenuItem创建)
    在MenuItem中(由Connect(MenuItem)创建)
    在Connect(MenuItem)中(由Context.Consumer创建)
    在触发器中(由工具提示创建)
    在工具提示中(由Context.Consumer创建)
    在工具提示中(由Context.Consumer创建)
    在MenuItem中(位于FortKnox.js:55)
    在_FortKnox中(由ConnectFunction创建)
    在ConnectFunction中(由Context.Consumer创建)
    在withRouter(Connect(_FortKnox))中(在PageSider / index.js:114)
    在ul中(由DOMWrap创建)
    在DOMWrap中(由SubPopupMenu创建)
    在SubPopupMenu中(由Connect(SubPopupMenu)创建)
    在Connect(SubPopupMenu)中(由Menu创建)
    在提供程序中(通过菜单创建)
    `
  • 同样的问题...我想创建一个权限组件作为HOC来包装Menu.Item,但antd不允许这样做...可悲

    我花了一些时间在这个问题上...

    '是可行的,您只需要将休息道具传递给ie。 Collapse.Panel(检查rc-panel的源代码以了解它)

    export const CustomPanel: React.FC = ({ header, children, ...props }) => {
      // do whatever you like
    
      return <Collapse.Panel header={header} {...props}>
        {children}
      </Collapse.Panel>
    };
    

    然后像这样使用它:

    <Collapse>
        <CustomPanel key="first" header="Header 1">Body</CustomPanel>
        <CustomPanel key="second" header="Header 2">Body</CustomPanel>
    </Collapse>
    

    在4.0版本中看到此解决方案真是太棒了!

    这绝对是当务之急。
    从字面上看,当需要特殊行为(有时甚至是简单的行为,例如授权)时,这些组件将无法使用。
    例如,我正在尝试创建一个动态加载的菜单,因此我会逐字显示一个禁用的Menu.Item作为名称,直到数据到达为止。
    这远非最佳。

    我花了一些时间在这个问题上...

    '是可行的,您只需要将休息道具传递给ie。 Collapse.Panel(检查rc-panel的源代码以了解它)

    虽然这是一个很棒的解决方案(确实!在我的项目中使用它),但您确实失去了一些功能。
    即,如果您的<SubMenu>不是<Menu>的直接子代,则defaultOpenKeys将不起作用。 😞

    刚遇到这个问题供参考。

    绝对需要在文档中进行确认。 严重沮丧地遇到这个问题(在其他一些次要问题中),这使我认真地重新考虑在项目中使用AntDesign。

    我不敢相信仍然没有解决办法。

    这确实需要解决。 大多数开发人员不只是直接使用组件。 这意味着我们可能希望集成更多功能,而这些功能是通过提供的api无法添加的。 我不会将HOC称为不常见或低优先级的用例。 这对React的组成性质至关重要。

    请修复此问题,并在修复该问题时将信息以及人们在此处发现的变通办法添加到您的正式文档中。

    请修复此问题,并在修复该问题时将信息以及人们在此处发现的变通办法添加到您的正式文档中。

    维护者可以使用PR,也可以根据需要发送PR进行文档更新。

    @ afc163

    我花了一些时间在这个问题上...

    并且这是可行的,您只需要将休息道具传递给ie。 Collapse.Panel(检查rc-panel的源代码以了解它)

    export const CustomPanel: React.FC = ({ header, children, ...props }) => {
      // do whatever you like
    
      return <Collapse.Panel header={header} {...props}>
        {children}
      </Collapse.Panel>
    };
    

    然后像这样使用它:

    <Collapse>
        <CustomPanel key="first" header="Header 1">Body</CustomPanel>
        <CustomPanel key="second" header="Header 2">Body</CustomPanel>
    </Collapse>
    

    有人可以在下面解释发生了什么。 还尝试将Panel包装在组件中。

    如果我使用此代码:

     <PersonalInfoPanel
                    header="header"
                    key={"personalInfo" + i}
                    extra={genExtra()}
                />
    

    PersonalInfoPanel

    function PersonalInfoPanel(props, ref) {
        return (
            <Panel header={props.header} key={props.key} extra={props.extra}>
    ...
    

    没用

    但是,一旦我改用这个:

    function PersonalInfoPanel(props, ref) {
        return (
            <Panel {...props}>
    ...
    

    它开始工作。
    有人可以解释为什么吗?

     <Panel {...props}>
    ...
    

    它开始工作。

    有人可以解释为什么吗?

    据我了解,父Collapse将需要设置除标头,键和其他项以外的道具(来自您无法使用的示例)。 来自父折叠的这些道具需要明确地放在自定义组件内的面板组件上。

    我猜您可以使用React Inspector来学习所有可能更改的道具,并将它们一一传递,但是... props语法可确保父项要添加到其子面板的任何内容都将被附加(包括但不限于您明确需要设置的那些)

    这个问题需要解决。
    许多(或几乎..)开发人员都希望使用库来自定义组件。

    例)
    该代码不起作用。 因为菜单和菜单项需要不透明的道具。

          <Menu>
            { menus.map((item) => {
              if (item.to) {
                return <Menu.Item title={item.title} />;
              }
              // some codes...
              return null;
            })}
          </Menu>
    

    @moonjoungyoung @adamerose
    您读过主题吗?
    您必须将rest道具传递给内部antd组件以使其工作。

    这是我在antd Menu内获取react-router NavLinks自定义组件和条件渲染的方法,尽管这需要修复-我浪费了,所以找到这个线程需要很多时间。

    _edit-没关系,selectedKeys无法正常工作_

    const Nav = withRouter(() => {
      const auth = store.isAuthenticated;
    
      return (
        <Menu selectedKeys={[history.location.pathname]} mode="horizontal">
          <NavItem id="/">Home</NavItem>
          {auth && <NavItem id="/create">Create Post</NavItem>}
          {!auth && <NavItem id="/sign-in">Sign In</NavItem>}
          {!auth && <NavItem id="/register">Register</NavItem>}
        </Menu>
      );
    });
    
    const NavItem = ({ ...props }) => (
      <Menu.Item {...props} key={props.id}>
        <NavLink exact to={props.id}>
          {props.children}
        </NavLink>
      </Menu.Item>
    );
    

    @moonjoungyoung @adamerose
    您读过主题吗?
    您必须将rest道具传递给内部antd组件以使其工作。

    您能看一下我上面的例子吗? 我以为我在该线程中应用了所有工作,但是仍然无法正常工作。 我正在传递道具并将它们散布在Menu.Item但是在活动时它仍然不会突出显示,并且组件树看起来像这样
    image

    我花了一些时间在这个问题上...

    并且这是可行的,您只需要将休息道具传递给ie。 Collapse.Panel(检查rc-panel的源代码以了解它)

    就我而言,我必须在“ {... props}”后面加上“ header = {calculated_header}”。 如果我不这样做,则面板标题不会显示。 我认为序列后面出现的“ {... props}”会覆盖“标题”信息。 当我在开头放置“ {... props}”时,它可以工作。 在这种情况下,我认为稍后出现的“标题”会覆盖道具中的“标题”信息。

    我对@ marcin-piela响应的适应性如下:

    export const CustomPanel: React.FC = ({ headerinfo, children, ...props }) => { // do whatever you like const calculated_header = {() => headerinfo.someinformation } return <Collapse.Panel {...props} header={calculated_header} > {children} </Collapse.Panel> };

    此页面是否有帮助?
    0 / 5 - 0 等级