简体   繁体   English

如何制作一个呈现 Ant Design TabPanes 数组的 React.FC?

[英]How to make a React.FC that renders an array of Ant Design TabPanes?

So, I'm trying to render some Tabs from Ant Design (Using 3.x here, as in my real app, but I bet it's exactly the same in 4.x ) that I need to reuse in different parts of my App.因此,我正在尝试从Ant 设计中渲染一些选项卡(在此处使用3.x ,就像在我的真实应用程序中一样,但我敢打赌它在4.x中完全相同)我需要在我的应用程序的不同部分重用。 Some of these tabs depend on dynamic data that comes from an schema retrieved by an API.其中一些选项卡依赖于来自由 API 检索的模式的动态数据。 Depending on that data the content of the tabs changes, or maybe some of the tabs don't even render.根据该数据,选项卡的内容会发生变化,或者某些选项卡甚至不会呈现。

Long story short, I've tried to simplify my use case with this snippet.长话短说,我试图用这个片段来简化我的用例。 I want to have a <DynamicTabPanes /> component that given the required data is able to handle the logic and return the needed TabPanes .我想要一个<DynamicTabPanes />组件,给定所需的数据能够处理逻辑并返回所需的TabPanes

Apparently, Ant Design doesn't like this.显然,Ant Design 不喜欢这样。 If I use my component like:如果我使用我的组件,例如:

<Tabs>
  <DynamicTabPanes data={someApiData} />
</Tabs>

I get these errors:我收到这些错误:

There must be tab property on children of Tabs. Tabs 的子项上必须有tab属性。

But, of course , if I provide a key and a tab property to my component, antd renders it as if it was a simple TabPane .但是,当然,如果我为我的组件提供一个key和一个tab属性, antd它呈现为就好像它是一个简单的TabPane See:看:

 const { Tabs } = antd; const { TabPane } = Tabs; const DynamicTabPanes = ({data}) => { return data.map((tab, index) => <TabPane tab={tab.label} key={index}>{tab.content}</TabPane>) } const someApiData = [{label: "First", content: "First Content"}, {label: "Second", content: "Second Content"}]; ReactDOM.render( <Tabs> <TabPane key="static-1" tab="Static Tab">Some static content</TabPane> <DynamicTabPanes data={someApiData} key="whatever" tab="I don't want this title..."/> </Tabs>, document.getElementById('root') );
 <link href="https://cdnjs.cloudflare.com/ajax/libs/antd/3.26.20/antd.css" rel="stylesheet"/> <div id="root"/> <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment-with-locales.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/antd/3.26.20/antd-with-locales.js" crossorigin="anonymous"></script>

I (kind of) made it work using a function instead of a FC, like this:我(有点)使用 function 而不是 FC 使其工作,如下所示:

 const { Tabs } = antd; const { TabPane } = Tabs; const renderDynamicTabPanes = (data) => { return data.map((tab, index) => <TabPane tab={tab.label} key={index}>{tab.content}</TabPane>) } const someApiData = [{label: "First", content: "First Content"}, {label: "Second", content: "Second Content"}]; ReactDOM.render( <Tabs> <TabPane key="static-1" tab="Static Tab">Some static content</TabPane> {renderDynamicTabPanes(someApiData)} </Tabs>, document.getElementById('root') );
 <link href="https://cdnjs.cloudflare.com/ajax/libs/antd/3.26.20/antd.css" rel="stylesheet"/> <div id="root"/> <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment-with-locales.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/antd/3.26.20/antd-with-locales.js" crossorigin="anonymous"></script>

But this doesn't seem like a good solution because:但这似乎不是一个好的解决方案,因为:

  1. React should be about Components, not interpolation. React 应该是关于组件,而不是插值。
  2. <DynamicTabPanes /> needs to use some hooks and you cannot use them in a function that is not a FC. <DynamicTabPanes />需要使用一些钩子,你不能在不是 FC 的 function 中使用它们。

Any ideas on how to make this work?关于如何使这项工作的任何想法? Thanks!谢谢!

Ok, I have made some investigation, so we have the following:好的,我做了一些调查,所以我们有以下内容:

  1. Ant-design uses Tabs and TabPane from 'rc-tabs' and all the logic related to tab rendering is located there github src Ant-design 使用“rc-tabs”中的TabsTabPane ,所有与选项卡渲染相关的逻辑都位于github src
  2. Tabs as wrapper component is responsible for rendering its children components.作为包装组件的Tabs负责渲染其子组件。 You can check that Tabs component iterates over it's immediate children in the parseTabList function src .您可以检查Tabs组件是否在parseTabList function src中迭代它的直接子级。 And it detects your DynamicTabPanes component as a single component.它会将您的DynamicTabPanes组件检测为单个组件。 Then Tabs component basing on the array of immediate children creates Navigation items TabNavList and Content Panels List TabPanelList (so the number of tabs will match the number of immediate children, which is two in your example).然后基于直接子级数组的选项卡组件创建导航项TabNavList和内容面板列表TabPanelList (因此选项卡的数量将与直接子级的数量相匹配,在您的示例中为两个)。
  3. So the answer is no, you cannot put your custom component instead of few other elements.所以答案是否定的,你不能把你的自定义组件而不是其他几个元素。 As far as I know, you cannot substitute one element with few elements before they have been rendered.据我所知,在渲染之前,您不能用很少的元素替换一个元素。

You can create your own pane like below and use your hooks there (it gone be separate hook for each pane):您可以像下面这样创建自己的窗格并在那里使用您的钩子(每个窗格都不再是单独的钩子):

const CustomPane = (props) => {
  if (!props.active) {
    return <div></div>;
  }
  return (
    <Fragment>
       My custom tab
      <TabPane {...props}>{props.children}</TabPane>
    </Fragment>
  );
};

You can do something like in the code below, but it is just another way to do the same as you did.您可以在下面的代码中执行类似的操作,但这只是您执行相同操作的另一种方式。 You can also replace staticPanel with an array of configs for static panels and concat it with dynamic and then make the mapping.您还可以将 staticPanel 替换为 static 面板的配置数组,并将其与动态连接,然后进行映射。

const DynamicTabPanes = (staticPanes, data) => {
  return staticPanes.concat(
    data.map((tab, index) => (
      <TabPane tab={tab.label} key={index}>
        {tab.content}
      </TabPane>
    ))
  );
};

function App() {
  const someApiData = [
    { label: "First", content: "First Content" },
    { label: "Second", content: "Second Content" },
  ];

  const staticPanes = [
    <TabPane key="static-1" tab="Static Tab">
      Some static content
    </TabPane>,
  ];

  return (
    <div className="App">
      <Tabs children={DynamicTabPanes(staticPanes, someApiData)} />
    </div>
  );
}

export default App;

Hope it will clarify a little bit the context of the issue.希望它能澄清一点问题的背景。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM