每次在带有Formik的React中完成输入字段时尝试创建一个计数器

时间:2019-04-21 06:11:35

标签: javascript reactjs forms function count

我正在尝试创建一个函数,该函数将在用户每次输入字段时递增。

我目前有一个父组件,该组件的状态被设置为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. example@domain.com"
        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.log(values);
   resetForm();
    }
     })(Formik);

The current UI

如何从父组件中的formik容器访问“值”,以便可以递增计数器状态,以便每次完成字段时动态计数器都会递增?我尝试创建一个回调函数,但由于我不知道formik组件容器的工作原理,因此无法正常传递该函数。

2 个答案:

答案 0 :(得分:1)

在这里:您也可以转到我创建的此沙箱:

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,
          handleChange,
          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();
                handleChange(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"));

答案 1 :(得分:1)

只需仔细看一下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

您最终将不得不根据您的逻辑对其进行修改。如果您有任何问题,请告诉我。 :)