React, Formik, Повторяемые поля формы с использованием массивов полей - PullRequest
1 голос
/ 22 октября 2019

Я пытаюсь выяснить, как использовать React с полевыми массивами Formik для встраивания повторяемых компонентов формы в мою форму.

У меня работает система (я думаю). Это комбинация предложений, полученных из 10+ источников, поэтому я начинаю думать, что я не на плантации, потому что должен быть очевидный способ установить это (а я просто не могу понять).

В настоящее время мой текущий подход генерирует предупреждение о том, что:

Компонент изменяет неконтролируемый ввод текста типа для управления. Входные элементы не должны переключаться с неуправляемых на управляемые (или наоборот). Выберите между использованием контролируемого или неконтролируемого элемента ввода в течение срока службы компонента. Дополнительная информация: https://reactjs.org/docs/forms.html#controlled-components

Моя песочница с кодом здесь: https://codesandbox.io/s/goofy-glade-lx65p?from-embed. Код из песочницы вставлен внизу этого поста для тех, кто предпочитает не использовать этот инструмент.

Вы видите, что форма отображается, а повторяемая встроенная форма может быть добавлена ​​и удалена. Однако во встроенной форме есть ошибка, которая гласит: this.props.formik.registerField не является функцией. (В 'this.props.formik.registerField (this.props.name, this)', 'this.props.formik.registerField' не определено)

Я не знаю, что это значит. Я нигде не использую то, что называется registerField. Я должен? Я видел этот пост , в котором описывается установка начального состояния, чтобы обойти это предупреждение, но если я сделаю это в форме запросов, то я получу пустую форму, отображаемую в главной форме (я не хочучто, я просто хочу, чтобы ссылка вставила один).

Кто-нибудь может увидеть, что я делаю не так с состоянием?

Форма:

import React from "react";
import { Link } from "react-router-dom";
import {
  Formik,
  Form,
  Field,
  FieldArray,
  ErrorMessage,
  withFormik
} from "formik";
// import * as Yup from "yup";
import Select from "react-select";
// import { fsDB, firebase, settings } from "../../../firebase";
import Requests from "./Requests";

import {
  Badge,
  Button,
  Col,
  ComponentClass,
  Feedback,
  FormControl,
  FormGroup,
  FormLabel,
  InputGroup,
  Table,
  Row,
  Container
} from "react-bootstrap";

const style2 = {
  paddingTop: "2em"
};

const initialValues = {
  title: "",
  Requests: [],
  createdAt: ""
};

class MainForm extends React.Component {
  state = {
    options: []
  };

  async componentDidMount() {
    // const fsDB = firebase.firestore(); // Don't worry about this line if it comes from your config.
    let options = [];
    // await fsDB.collection("abs_for_codes").get().then(function (querySnapshot) {
    // querySnapshot.forEach(function(doc) {
    //     console.log(doc.id, ' => ', doc.data());
    //     options.push({
    //         value: doc.data().title.replace(/( )/g, ''),
    //         label: doc.data().title + ' - ABS ' + doc.id
    //     });
    //     });
    // });
    this.setState({
      options
    });
  }

  handleSubmit = (formState, { resetForm }) => {
    // Now, you're getting form state here!
    const payload = {
      ...formState,
      createdAt: firebase.firestore.FieldValue.serverTimestamp()
    };
    console.log("formvalues", payload);

    // fsDB
    //   .collection("project")
    //   .add(payload)
    //   .then(docRef => {
    //     console.log("docRef>>>", docRef);
    //     resetForm(initialValues);
    //   })
    //   .catch(error => {
    //     console.error("Error adding document: ", error);
    //   });
  };

  render() {
    const { options } = this.state;

    return (
      <Formik
        initialValues={initialValues}
        onSubmit={this.handleSubmit}
        render={({
          errors,
          status,
          touched,
          setFieldValue,
          setFieldTouched,
          handleSubmit,
          isSubmitting,
          dirty,
          values,
          arrayHelers
        }) => {
          return (
            <div>
              <Form>
                <Table responsive>
                  <thead>
                    <tr>
                      <th>#</th>
                      <th>Element</th>
                      <th>Insights</th>
                    </tr>
                  </thead>
                </Table>
                {/*General*/}
                <h5 className="formheading">general</h5>
                <Table responsive>
                  <tbody>
                    <tr>
                      <td>1</td>
                      <td>
                        <div className="form-group">
                          <label htmlFor="title">Title</label>
                          <Field
                            name="title"
                            type="text"
                            className={
                              "form-control" +
                              (errors.title && touched.title
                                ? " is-invalid"
                                : "")
                            }
                          />
                          <ErrorMessage
                            name="title"
                            component="div"
                            className="invalid-feedback"
                          />
                        </div>
                      </td>
                      <td className="forminsight">No insights</td>
                    </tr>
                  </tbody>
                </Table>
                {/*Method*/}
                {/* <SoPTip /> */}

                {/*Resources s*/}
                <Table responsive>
                  <tbody>
                    <tr>
                      <td>
                        <label htmlFor="Requests">Request</label>

                        <FieldArray
                          name="Requests"
                          render={arrayHelpers => (
                            <React.Fragment>
                              {values.Requests.map((funding, i) => (
                                <Requests
                                  setFieldValue={setFieldValue}
                                  arrayHelpers={arrayHelpers}
                                  values={values}
                                  data={funding}
                                  key={i}
                                  index={i}
                                />
                              ))}
                              <div>
                                <Button
                                  variant="link"
                                  size="sm"
                                  onClick={() =>
                                    arrayHelpers.push({
                                      title: "",
                                      description: "",
                                      source: "",
                                      disclosure: "",
                                      conflicts: ""
                                    })
                                  }
                                >
                                  Add request
                                </Button>
                              </div>
                            </React.Fragment>
                          )}
                        />
                      </td>
                      <td className="forminsight">No insights</td>
                    </tr>
                  </tbody>
                </Table>
                <div className="form-group">
                  <Button
                    variant="outline-primary"
                    type="submit"
                    id="ProjectId"
                    onClick={handleSubmit}
                    disabled={!dirty || isSubmitting}
                    onSubmit={values => console.log(values)}
                  >
                    Save
                  </Button>
                </div>
              </Form>
            </div>
          );
        }}
      />
    );
  }
}

export default MainForm;

Запрос повторяетсяформа:

import React from "react";
import { Field } from "formik";
import Select from "react-select";

import { Table, Button } from "react-bootstrap";

const Currencies = [
  { value: "usd", label: "United States Dollars (USD)" },
  { value: "nzd", label: "New Zealnd Dollars (NZD)" },
  { value: "gbp", label: "Pounds Sterling (GBP)" },
  { value: "cad", label: "Canadian Dollars (CAD)" }
];

class Requests extends React.Component {
  render() {
    const {
      index,
      values,
      setFieldValue,
      setFieldTouched,
      arrayHelpers,
      remove
    } = this.props;

    return (
      <div>
        <Table responsive>
          <tbody>
            <tr>
              <td>
                <div className="form-group">
                  <label htmlFor="RequestsTitle">Title</label>

                  <Field
                    name={`Requests.${index}.title`}
                    placeholder="Add a title"
                    className="form-control"
                  />
                </div>
              </td>
            </tr>
            <tr>
              <td>
                <div className="form-group">
                  <label htmlFor="RequestsSource">Source</label>
                  <Field
                    name={`Requests.${index}.source`}
                    component="textarea"
                    rows="10"
                    placeholder="Leave blank and skip ahead if you don't"
                    className="form-control"
                  />
                </div>
              </td>
            </tr>
            <tr>
              <td>
                <div className="form-group">
                  <label htmlFor="Currency">Select your currency</label>

                  <Select
                    key={`my_unique_select_keyCurrency`}
                    name={`Requests.${index}.Currency`}
                    className={"react-select-container"}
                    classNamePrefix="react-select"
                    onChange={({ value: selectedOption }) => {
                      console.log(selectedOption);
                      setFieldValue(
                        `Requests.${index}.Currencies`,
                        selectedOption
                      );
                    }}
                    onBlur={setFieldTouched}
                    options={Currencies}
                  />
                </div>
              </td>
              <td className="forminsight">No insights</td>
            </tr>
            <tr>
              <td>
                <div className="form-group">
                  <label htmlFor="RequestsAmount">
                    What amount of funding are you seeking?
                  </label>
                  <Field
                    name={`Requests.${index}.amount`}
                    type="text"
                    placeholder="Enter a number without a currency symbol"
                    className={"form-control"}
                  />
                </div>
              </td>
              <td className="forminsight">No insights</td>
            </tr>
            <tr>
              <td>
                <div className="form-group">
                  <label htmlFor="RequestsDisclosure">Disclosure</label>
                  <Field
                    name={`Requests.${index}.disclosure`}
                    component="textarea"
                    rows="10"
                    placeholder="Consider."
                    className="form-control"
                  />
                </div>
              </td>
            </tr>
            <tr>
              <td>
                <div className="form-group">
                  <label htmlFor="RequetsConflicts">Conflicts</label>
                  <Field
                    name={`Requests.${index}.conflicts`}
                    component="textarea"
                    rows="10"
                    placeholder="Take a look at the checklist. "
                    className="form-control"
                  />
                </div>
              </td>
              <td className="forminsight">No insights</td>
            </tr>
            <tr>
              <td>
                <div className="form-group">
                  <label htmlFor="RequestsBudget">
                    Do you have a budget for how this funding will be deployed?
                  </label>
                  <Field
                    name={`Requests.${index}.budget`}
                    component="textarea"
                    rows="10"
                    placeholder="Leave blank if you don't."
                    className="form-control"
                  />
                </div>
              </td>
              <td className="forminsight">No insights</td>
            </tr>
          </tbody>
        </Table>
        <Button
          variant="outline-secondary"
          size="sm"
          onClick={() => arrayHelpers.remove(index)}
        >
          Remove this request
        </Button>
      </div>
    );
  }
}

export default Requests;

1 Ответ

0 голосов
/ 22 октября 2019

Причина, по которой я нахожу это предупреждение, состоит в том, что у вас Requests в вашем initialValues, но вы используете fundingRequests в своей форме.
, когда я изменил

<Field
  name={`fundingRequests.${index}.title`}
  placeholder="Add a title"
  className="form-control"
 />

на

 <Field
   name={`Requests.${index}.title`}
   placeholder="Add a title"
   className="form-control"
 />

предупреждений больше не будет. дайте мне знать, если это не решит проблему

...