Я пытаюсь выяснить, как использовать 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;