【问题标题】:React/Antd: Dynamic form fields based on JSON responseReact/Antd:基于 JSON 响应的动态表单字段
【发布时间】:2019-08-23 23:55:23
【问题描述】:

我正在尝试创建一个基于 JSON 响应动态映射字段的表单。

我目前有一个正在设置状态的虚拟对象,但最后阶段将接收来自外部 API 调用的数据。数据集可能会随着时间的推移而变化,根据业务需要添加或删除键/值。取而代之的是,我需要创建一个智能组件,它采用一组初始数据并为对象中的每个键/值对映射一个“只读”字段。

第二个问题是实际的表单布局。我在下面有一个初始脚手架,我只对列和行进行了硬编码。如何实现从数据响应中创建两列行的逻辑?

非常感谢您对此的任何想法/帮助!

代码:

import React, { Component } from 'react';
import { render } from 'react-dom';
import { Form, Button, Input, Row, Col } from 'antd';
import "antd/dist/antd.css";
import './style.css';

class OpportunityDetails extends Component {
constructor() {
      super();
    this.state = {
      disabled: true,
      formLayout: 'horizontal',
      opportunityDetails: [
          {
              CustomerName: "",
              Field2: "Some data",
              Field3: "Some data",
              Field4: "Some data",
              Field5: "Some data",
              Field6: "Some data",
              Field7: "Some data",
              Field8: "Some data",
              Field9: "Some data",
              Field10: "Some data",
              Field11: "Some data",
              Field12: "Some data",
              Field13: "Some data",
              Field14: "Some data",
              Field15: "Some data"
          }
      ]
    };
    this.toggleSwitch = this.toggleSwitch.bind(this)
}

  toggleSwitch() {
    this.setState(previousState => ({
      disabled: !previousState.disabled,
      enabled: previousState.disabled
    }))
  }

  modifyRoute(){
    alert("Sending you to the modify floor");
  }

  uploadRoute(){
    alert("Sending you to the upload sector!")
  }

  render() {
    const { disabled } = this.state;
    const { enabled } = this.state;


    return (
      <div className={}>

 /// Button Group
      <Row type="flex" justify="space-around">
        <Col span={4}>
          <Button disabled={disabled} onClick={this.modifyRoute}>Modify Docs</Button>
        </Col>
        <Col span={4}>
          <Button disabled={disabled} onClick={this.uploadRoute}>Upload Docs</Button>
        </Col>
        <Col span={4}>
          <Button disabled={enabled} onClick={this.toggleSwitch}>
            Unlock Quote
          </Button>
        </Col>
      </Row>

/// Form section with columns and rows for all key/value pairs
      <Row type="flex" justify="space-around">
      <Col span={10}>
        <Form.Item label={key}>
          <Input placeholder={value} />
        </Form.Item>
      </Col>
      <Col span={10}>
        <Form.Item label={key}>
          <Input placeholder="{value} />
        </Form.Item>
      </Col>
      </Row>
      <Row type="flex" justify="space-around">
      <Col span={10}>
        <Form.Item label={key}>
          <Input placeholder={value} />
        </Form.Item>
      </Col>
      <Col span={10}>
        <Form.Item label={key}>
          <Input placeholder={value} />
        </Form.Item>
      </Col>
      </Row>
            <Row type="flex" justify="space-around">
      <Col span={10}>
        <Form.Item label={key}>
          <Input placeholder={value} />
        </Form.Item>
      </Col>
      <Col span={10}>
        <Form.Item label={key}>
          <Input placeholder={value} />
        </Form.Item>
      </Col>
      </Row>
      <Row type="flex" justify="space-around">
      <Col span={10}>
        <Form.Item label={key}>
          <Input placeholder={value} />
        </Form.Item>
      </Col>
      <Col span={10}>
        <Form.Item label={key}>
          <Input placeholder={value} />
        </Form.Item>
      </Col>
      </Row>

      </div>
    );
  }
}

render(<OpportunityDetails />, document.getElementById('root'));

【问题讨论】:

  • 迭代函数有问题吗?
  • 我不太清楚如何设置迭代函数来创建 Antd 元素
  • 对象和数组的迭代与 Antd 或 React 无关,它是基本的 JavaScript 函数。我建议您花更多时间学习 JavaScript,然后 React,您将能够将所有内容应用到每个 UI 库、Antd、Bootstrap Material ...
  • 我知道如何迭代一个对象,但 Antd 显示标题和文本的方式让我很反感。我可以从opportunityDetails.map(key =&gt; (&lt;Row type="flex" justify="space-around"&gt; &lt;Col span={10}&gt; &lt;Form.Item label={key=opportunityDetails.key}&gt; &lt;Input placeholder={opportunityDetail.value} /&gt; &lt;/Form.Item&gt; &lt;/Col&gt; 之类的返回部分设置映射,但由于您如何定义 Title 和实际 &lt;Form.item&gt; 组件中的文本,这与 Antd 的关系并不好
  • 这就是问题所在,map 在数组之上,但是在你的数组中你有一个对象,你不能在对象上映射,你应该使用,例如对于每个键,值对

标签: reactjs forms parent-child dynamically-generated antd


【解决方案1】:

认真对待阿米尔的评论。一旦你这样做了,你可能会重组你的数据,使其更方便(和可读):

我不知道为什么opportunityDetails 必须是一个数组,反正我已经适应了。尽管它会增加您所看到的复杂性

1.) 这就是您希望数据的样子(稍后您会明白为什么):

/*[
   { itemKey: "CustomerName", itemValue: "" },
   { itemKey: "Field2", itemValue: "Some data" }
   .... and so on
]*/


opportunityDetails: [
  {
    CustomerName: "",
    Field2: "Some data",
    Field3: "Some data",
    Field4: "Some data",
    Field5: "Some data",
    Field6: "Some data",
    Field7: "Some data",
    Field8: "Some data",
    Field9: "Some data",
    Field10: "Some data",
    Field11: "Some data",
    Field12: "Some data",
    Field13: "Some data",
    Field14: "Some data",
    Field15: "Some data"
  }
].map(obj => {
  const objKeys = Object.keys(obj);
  return objKeys.map(itemKey => {
    return {
      itemKey,
      itemValue: obj[itemKey]
    };
  });
})

以下步骤和模式是特定于 JSX(或反应)的;我想说的是这是在反应中呈现array of JSX elements 的最常见方式:

2.) 创建一个返回 JSX 数组的方法,我使用 .map 因为 .forEach 不起作用(您可能想自己搜索原因)。

renderDynamicElWrapper() {
  return this.state.opportunityDetails.map(items => {
    return (
      <Row type="flex" justify="space-around">
        {this.renderDynamicEl(items)}
      </Row>
    );
  });
 }

假设opportunityDetails 将有超过1 个项目,我们需要有另一个类似于上面的方法和迭代

  renderDynamicEl(els) {
    return els.map(el => {
      return (
        <Col span={10}>
          <Form.Item label={el.itemKey}>
            <Input placeholder={el.itemValue} />
          </Form.Item>
        </Col>
      );
    });
  }

3.) 最后,render 方法的返回结果如下所示:

return (
      <div>
        <Row type="flex" justify="space-around">
          <Col span={4}>
            <Button disabled={disabled} onClick={this.modifyRoute}>
              Modify Docs
            </Button>
          </Col>
          <Col span={4}>
            <Button disabled={disabled} onClick={this.uploadRoute}>
              Upload Docs
            </Button>
          </Col>
          <Col span={4}>
            <Button disabled={enabled} onClick={this.toggleSwitch}>
              Unlock Quote
            </Button>
          </Col>
        </Row>
        {this.renderDynamicElWrapper()}
      </div>
    );
  }

P.S:我建议掌握 .map 以及如何从方法中返回 jsx 数组,因为 %100 的时间你会在 React 项目中遇到相同的模式。

【讨论】:

  • 我们得到的数据响应在数组中。我们正在与 API 团队合作,让他们将响应作为对象返回。我可以使用上述逻辑来映射具有嵌套对象的对象吗?
  • 而不是像您列出的一组单独的对象作为如何构造我的数据的示例,例如{ itemKey: "CustomerName", itemValue: "" }, { itemKey: "Field2", itemValue: "Some data" }
  • @JCalkins89 是的。你试过了吗?它实际上在我身边工作。 opportunityDetails 将变为数组数组而不是对象数组
  • 当opportunityDetails 是具有键/值对的单个对象的数组但当我将数据更改为对象数组时标题字段全部变为itemKey 和itemValue 和应该是 Titles 的值都转移到字段中。我在这里有一个 Stack Blitz 显示我的意思(stackblitz.com/edit/react-5t7vmv)。如果响应是嵌套对象的对象,是否有更好的映射方法?
  • 我对#1 的不好我可能没有表达我的意思足够好。确实,我已经为您完成了转换/映射部分。如果您只是还原原始的opportunityDetails,您将从 Stack Blitz 中获得正确的结果。如果您注意到构造函数中的opportunityDetails....map 函数,那么.map 完成了重构opportunityDetails 的工作
【解决方案2】:
<Row type="flex" justify="space-around">
  <Col span={10}>
     {opportunityDetails.map(detail=>{
          return detail.forEach(([key,value])=>(
               <Form.Item label={key}>
                   <Input placeholder={value} />
               </Form.Item>
             )
          )
      })}
  </Col>
</Row>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-08-10
    • 2017-02-22
    • 2021-05-01
    • 2020-03-24
    • 1970-01-01
    • 2018-01-20
    • 2020-10-29
    • 2021-11-30
    相关资源
    最近更新 更多