无法从选择框中选择项目/无法在输入字段中写入。我是否错误地处理了“密钥”?

时间:2019-03-13 11:44:15

标签: javascript reactjs typescript antd

我正在用下面给出的代码编写组件,渲染后的样子如下:

enter image description here

我已经使用antd组件来渲染字段。我面临的问题是我既无法从选择框中进行选择,也无法在输入字段中进行书写,如下所示。我有一种感觉,我在从key获得的render方法中不恰当地将React的mocFields用于getMOCField

import React, { Component } from "react";
import { Button, Icon, Select, Form, Input } from "antd";
const FormItem = Form.Item;
const Option = Select.Option;
import { FormComponentProps } from "antd/lib/form/Form";

type state = {
  mocFields: JSX.Element[]
};

export class MOC extends Component<FormComponentProps, state> {
  constructor(props) {
    super(props);
    this.state = {
      mocFields: []
    };
    this.addMOCField = this.addMOCField.bind(this);
    this.removeMOCField = this.removeMOCField.bind(this);
  }

  componentDidMount() {}

  componentWillReceiveProps(nextProps) {}

  removeMOCField(key, event: React.MouseEvent<HTMLElement>) {
    event.preventDefault();
    const { mocFields } = this.state;

    mocFields.splice(key, 1);

    this.setState({
      mocFields
    });
  }

  getMOCFieldFooter() {
    return (
      <div className="d-flex justify-content-between small">
        <div className="inline-block">
          <Button
            type="primary"
            shape="circle"
            icon="plus"
            ghost
            size="small"
            className="d-font mr-1"
            onClick={this.addMOCField}
          />
          <div
            className="text-primary pointer d-font inline-block letter-spacing-1"
            onClick={this.addMOCField}
          >
            Add another&nbsp;
          </div>
          <div className="d-font inline-block letter-spacing-1">or&nbsp;</div>
          <div className="text-primary pointer d-font inline-block letter-spacing-1">
            Create a new MOC
          </div>
        </div>
      </div>
    );
  }

  getMOCField(key) {
    const { getFieldDecorator } = this.props.form;

    return (
      <div className="d-flex justify-content-between">
        <div className="inline-block">
          <FormItem label="Select MOC">
            {getFieldDecorator(`selected_moc[${key}]`, {
              rules: [
                {
                  required: true,
                  message: "Please select moc"
                }
              ]
            })(
              <Select>
                <Option value={"A"}>A</Option>
                <Option value={"B"}>B</Option>
              </Select>
            )}
          </FormItem>
        </div>

        <div className="inline-block">
          <FormItem label="Recovery (%)">
            {getFieldDecorator(`recovery_percentage[${key}]`, {
              rules: [
                {
                  required: true,
                  message: "Please input the recovery percentage"
                }
              ]
            })(<Input type="number" step="0.000001" />)}
          </FormItem>
        </div>
        <div className="inline-block pointer">
          <span>
            <Icon type="close" onClick={this.removeMOCField.bind(this, key)} />
          </span>
        </div>
      </div>
    );
  }

  addMOCField(event: React.MouseEvent<HTMLElement>) {
    event.preventDefault();
    const { mocFields } = this.state;
    const MOCField = this.getMOCField(mocFields.length);
    mocFields.push(MOCField);

    this.setState({
      mocFields
    });
  }

  getAddMOCButton() {
    return (
      <div className="d-flex w-100 mt-3">
        <Button
          type="primary"
          ghost
          className="w-100"
          onClick={this.addMOCField}
        >
          <Icon type="plus-circle" />
          Add MOC
        </Button>
      </div>
    );
  }

  render() {
    const { mocFields } = this.state;
    const mocButton = this.getAddMOCButton();
    const toRender =
      mocFields.length > 0 ? (
        <div className="w-100 p-2 gray-background br-25">
          {mocFields.map((f, index) => (
            <div key={index}>{f}</div>
          ))}
          {this.getMOCFieldFooter()}
        </div>
      ) : (
        mocButton
      );

    return toRender;
  }
}

这可能是什么原因?我做错了什么?目前,上述组件的呈现方式如下:

  • 如果mocFields中的字段数为零,那么将显示一个用于添加新字段的按钮。
  • 按下按钮后,mocField会被填充选择框和输入字段,如上所示。 div的键是在render方法期间确定的。

1 个答案:

答案 0 :(得分:1)

似乎侦听器一旦存储在数组中就无法工作。我尝试在getMOCField函数中内联对render的调用,并且它可以正常工作。这是我为了使其工作而进行的更改:

class MOC extends Component {
  // ...

  addMOCField(event) {
    event.preventDefault();

    const { mocFields } = this.state;

    // We only keep inside the state an array of number
    // each one of them represent a section of fields.
    const lastFieldId = mocFields[mocFields.length - 1] || 0;
    const nextFieldId = lastFieldId + 1;

    this.setState({
      mocFields: mocFields.concat(nextFieldId),
    });
  }

  removeMOCField(key, event) {
    event.preventDefault();

    this.setState(prevState => ({
      mocFields: prevState.mocFields.filter(field => field !== key)
    }));
  }

  render() {
    const { mocFields } = this.state;
    const mocButton = this.getAddMOCButton();
    const toRender =
      mocFields.length > 0 ? (
        <div className="w-100 p-2 gray-background br-25">
          {/* {mocFields.map((f, index) => (
                <div key={index}>{f}</div>
              ))} */}
          {mocFields.map(fieldIndex => (
            <div key={fieldIndex}>{this.getMOCField(fieldIndex)}</div>
          ))}
          {this.getMOCFieldFooter()}
        </div>
      ) : (
        mocButton
      );

    return toRender;
  }
}