Я пытаюсь создать функцию, которая будет увеличиваться каждый раз, когда пользователь вводит поле.
В настоящее время у меня есть родительский компонент, который имеет состояние со значением счетчика, равным 0 . мой дочерний компонент - это компонент-контейнер Formik, который содержит и обрабатывает мое поле.
// Родительский компонент
import React, { Component } from "react";
import Formik from "./Formik";
export default class BountyPage extends Component {
state = {
total: 0
};
render() {
return (
<div className = "bountyPage">
<div className = "total_container">
<p className = "total_title pt-2">SERV</p>
<h1 className = "total_sub">{this.state.total}</h1>
</div>
<Formik />
</div>
);
}
}
// Дочерний компонент
const Formik = ({ values, errors, touched, isSubmitting,
setFieldValue }) => (
<Form className = "form">
{touched.lastName &&
values.lastName &&
touched.firstName &&
values.firstName ? (
<Row>
<Col className = "result_text pulse animated p-4">
<b>Welcome</b>{" "}
<span
className = "clickable_text"
onClick = {async () => {
await setFieldValue("firstName", "");
await setFieldValue("lastName", "");
}}
>
{values.firstName} {values.lastName}
</span>
</Col>
</Row>
) : (
<Row className = "glow_form p-1">
<Col md = {6}>
<FormGroup>
<Label for = "firstName">First Name</Label>
<Field
type = "firstName"
name = "firstName"
placeholder = "ie. John"
className = "form-control"
/>
{touched.firstName && errors.firstName && <p>
{errors.firstName}</p>}
</FormGroup>
</Col>
<Col md = {6}>
<FormGroup>
<Label for = "lastName">Last Name</Label>
<Field
type = "lastName"
name = "lastName"
placeholder = "ie. Doe"
className = "form-control"
/>
{touched.lastName && errors.lastName && <p>
{errors.lastName}</p>}
</FormGroup>
</Col>
</Row>
)}
<Row className = "glow_form pt-1">
<Col>
<FormGroup>
<Label for = "email">Bittrex Email Address</Label>
<Field
type = "email"
name = "email"
placeholder = "ie. [email protected]"
className = "form-control"
/>
{touched.email && errors.email && <p>{errors.email}</p>}
</FormGroup>
</Col>
</Row>
<Row>
<Col className = "col_container">
<FormGroup>
<div className = "switch_container">
<p>I’m a business owner</p>
<label className = "switch">
<Field type = "checkbox" name = "switch1" checked=
{values.switch1} />
<span className = "slider round" />
</label>
</div>
</FormGroup>
{values.switch1 && (
<Row className = "bounceInDown animated">
<Col md = {6}>
<FormGroup>
<Field
type = "text"
name = "industryText"
placeholder = "ie. Automotive"
className = "form-control"
/>
</FormGroup>
</Col>
<Col md = {6}>
<FormGroup>
<Field
type = "number"
name = "locationText"
placeholder = "ie. 1-2"
className = "form-control"
/>
</FormGroup>
</Col>
</Row>
)}
</Col>
</Row>
{values.firstName && values.lastName ? (
<Row>
<Col className = "text-center">
{values.email ? (
<span>
<Button
type = "submit"
disabled = {isSubmitting}
className = "submit_btn"
>
Review
</Button>
<hr />
</span>
) : (
<span>
<Button
type = "submit"
disabled = {isSubmitting}
className = "submit_btn"
>
Submit
</Button>
<hr />
</span>
)}
</Col>
</Row>
) : (
""
)}
</Form>
);
export default withFormik({
mapPropsToValues({
firstName,
lastName,
email,
switch1,
industryText,
locationText,
checkbox
}) {
return {
firstName: firstName || "",
lastName: lastName || "",
email: email || "",
switch1: switch1 || false,
industryText: industryText || "",
locationText: locationText || "",
checkbox: checkbox || false
};
},
validationSchema: Yup.object().shape({
firstName: Yup.string()
.max(40, "Please enter no more than 40 characters")
.required("Please enter your first name"),
lastName: Yup.string()
.max(40, "Please enter no more than 40 characters")
.required("Please enter a last name"),
email: Yup.string()
.email("Please enter a valid email")
.required("Please enter an email")
}),
handleSubmit(values, { resetForm }) {
console.info(values);
resetForm();
}
})(Formik);
Как мне получить доступ к этим «значениям» из контейнера formik в моем родительском компоненте, чтобы я мог увеличивать состояние счетчика, чтобы мой динамический счетчик увеличивался каждый раз, когда поле заполняется? Я попытался создать функцию обратного вызова, но не передал функцию должным образом, так как не знаю, как работает контейнер компонента formik.
Могу ли я получить доступ к handleChangeEvent в этом родительском компоненте, чтобы сделать функцию приращения?
Вам нужно развернуть обработчик родительского компонента onFormikValueChange и вызвать его в handleChangeEvent фактической функции formik
Я впервые использую Formik, поэтому я немного не уверен, как бы я это сделал.
Так вот что я пытаюсь. Я собираюсь создать функцию приращения в своем родительском компоненте, и я хочу развернуть эту функцию до моего контейнера formik, а затем использовать ее, чтобы увидеть, могу ли я передать значения.
Я уверен, что у вас есть способ отказаться от значений, просто определив обработчик событий из вашего родительского компонента. Я думаю, что настоящая проблема будет заключаться в том, как определить, действительно ли поле заполнено?
@MateenKazia Предоставил ответ
@MateenKazia, пожалуйста, посмотрите, поможет ли вам мой ответ ниже.
@MateenKazia вы смогли найти решение :)?
@yourfavoritedev Я собираюсь проверить это прямо сейчас. Честно говоря, все, что мне нужно знать, это как получить доступ к реквизитам из компонента formik в его родительский компонент.
@yourfavoritedev похоже, что с вашим методом это сработает, но мне придется удалить мою схему проверки
@MateenKazia. Мне было бы интересно посмотреть, как мы можем объединить наши методы вместе. Я думаю, мы можем сохранить вашу validationSchema. Единственное, что нам действительно нужно сделать, это вызвать функцию обновления состояния из родительского компонента всякий раз, когда <Field/> вызывает свой обработчик проверки, как я упоминал ниже. У Formik должна быть некоторая документация о том, как подключиться к validationSchema, когда вы вызываете функцию внутри компонента. Наверное, в своем реквизите. :)
Также я думаю, что плохо справился с примерами того, что я пытаюсь сделать. Я пытаюсь проверить создание счетчика в моем родительском компоненте и посмотреть, существуют ли значения, если они существуют, а затем увеличить на 1
Нет, я понял эту часть, ха-ха.
@yourfavoritedev сможет использовать Teamviewer со мной? Я возмещу вам ваше время?
Давайте продолжить обсуждение в чате.
@yourfavoritedev teamviewer закрылся до того, как я получил ваш контакт =(



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вот он: Вы также можете зайти в эту песочницу, которую я создал:
https://codesandbox.io/s/0ovjx025lp
import React from "react";
import { render } from "react-dom";
import { Formik } from "formik";
import * as Yup from "yup";
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
counter: 0
};
}
increment = () => {
this.setState({
counter: this.state.counter + 1
});
};
decrement = () => {
this.setState({
counter: this.state.counter - 1
});
};
render() {
return (
<React.Fragment>
<h3>Counter:: {this.state.counter}</h3>
<App handleIncrement = {this.increment} />
</React.Fragment>
);
}
}
const App = originalProps => (
<div className = "app">
<h1>
Basic{" "}
<a
href = "https://github.com/jaredpalmer/formik"
target = "_blank"
rel = "noopener"
>
Formik
</a>{" "}
Demo
</h1>
<Formik
initialValues = {{ email: "" }}
onSubmit = {(values, { setSubmitting }) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
setSubmitting(false);
}, 500);
}}
validationSchema = {Yup.object().shape({
email: Yup.string()
.email()
.required("Required")
})}
>
{props => {
const {
values,
touched,
errors,
dirty,
isSubmitting,
handleChangeEvent,
handleBlur,
handleSubmit,
handleReset
} = props;
return (
<form onSubmit = {handleSubmit}>
<label htmlFor = "email" style = {{ display: "block" }}>
Email
</label>
<input
id = "email"
placeholder = "Enter your email"
type = "text"
value = {values.email}
onChange = {e => {
originalProps.handleIncrement();
handleChangeEvent(e);
}}
onBlur = {handleBlur}
className = {
errors.email && touched.email
? "text-input error"
: "text-input"
}
/>
{errors.email && touched.email && (
<div className = "input-feedback">{errors.email}</div>
)}
<button
type = "button"
className = "outline"
onClick = {handleReset}
disabled = {!dirty || isSubmitting}
>
Reset
</button>
<button type = "submit" disabled = {isSubmitting}>
Submit
</button>
</form>
);
}}
</Formik>
</div>
);
render(<Parent />, document.getElementById("root"));
Я получаю, что originalProps не определен =(
Только что внимательно посмотрел документацию Formik. У них есть довольно подробный пример того, что вы можете сделать здесь: https://jaredpalmer.com/formik/docs/api/field#validate.
С другой стороны, я создал песочницу, чтобы вы могли понять, как воспроизвести то, что вы ищете.
Родительский компонент:
import React from "react";
import Child from "./Child";
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
counter: 0
};
}
handleIncrement = event => {
this.setState({
counter: this.state.counter + 1
});
};
handleDecrement = event => {
this.setState({
counter: this.state.counter - 1
});
};
render() {
return (
<div>
<h3>Parent Counter: {this.state.counter}</h3>
<Child
onComplete = {this.handleIncrement}
onInvalidate = {this.handleDecrement}
/>
</div>
);
}
}
export default Parent;
Дочерний компонент:
import React from "react";
import { Formik, Form, Field } from "formik";
class Child extends React.Component {
state = {
emailValid: false,
passwordValid: false
};
//value is passed in implicitly from the Field
validateEmail = value => {
//insert email logic here
if (value.includes("@") && !this.state.emailValid) {
this.setState({
emailValid: true
});
//if field is complete then increase counter on parent
this.props.onComplete();
} else if (!value.includes("@") && this.state.emailValid) {
this.setState({
emailValid: false
});
//if field was valid and no longer is valid
this.props.onInvalidate();
}
};
validatePassword = value => {
//insert password logic here
if (value.length >= 6 && !this.state.passwordValid) {
this.setState({
passwordValid: true
});
this.props.onComplete();
} else if (value.length < 6 && this.state.passwordValid) {
this.setState({
passwordValid: false
});
//if field was valid and no longer is valid
this.props.onInvalidate();
}
};
handleSubmit = event => {
event.preventDefault();
};
render() {
return (
<div className = "app">
<Formik
initialValues = {{ email: "", username: "" }}
onSubmit = {this.handleSubmit}
>
{({ errors, touched }) => (
<Form>
<Field validate = {this.validateEmail} name = "email" type = "email" />
{errors.email && touched.email ? <div>{errors.email}</div> : null}
<Field validate = {this.validatePassword} name = "password" />
{errors.password && touched.password ? (
<div>{errors.username}</div>
) : null}
<button type = "submit">Submit</button>
</Form>
)}
</Formik>
</div>
);
}
}
export default Child;
https://codesandbox.io/s/8x736oqwq0
В конечном итоге вам придется изменить его в соответствии с вашей логикой. Дайте мне знать, если у вас есть вопросы. :)
эй, приятель, можешь проверить сообщение обсуждения?
Вы можете использовать событие handleChangeEvent, предоставленное formik