禁用的 Formik 字段的重置值

Reset value of disabled Formik Field

我正在尝试 clear/reset 复选框禁用后的值。我最初认为我是通过使用 React 条件并将值设置为空字符串来实现此目的的,但如果复选框在被禁用之前已被激活,那么该值仍会被提交。这种行为似乎不正确,因为我的印象是未提交禁用的输入字段值?

React 条件表示如果表单被禁用,则复选框的值应该为空。

我正在使用 Formik 处理带有 Yup 模式验证的表单。

下面是我的表单的完整代码。

提前谢谢你。

import axios from "axios";
import * as Yup from "yup";
import Head from "next/head";
import Link from "next/link";
import Router from "next/router";
import { useState } from "react";
import Error from "../components/error";
import Layout from "../components/layout";
import Button from "react-bootstrap/Button";
import Spinner from "react-bootstrap/Spinner";
import { Formik, Form, Field, ErrorMessage } from "formik";

var instagram = false;
var twitter = false;
var github = false;

const validationSchema = Yup.object({
  firstName: Yup.string()
    .max(15, "Must be 15 characters or less"),
  email: Yup.string().email("Invalid email address").required("Required"),
  username: Yup.string()
    .test(
      'valid-instagram', "Instagram: may contain only alphanumeric characters, periods, and underscores", function (username){
        var instagramRegex = new RegExp(/^(?!.*\.\.)(?!.*\.$)[^\W][\w.]{0,29}$/);
        var instagramRes = instagramRegex.test(username)
        if (instagramRes) { // if res is true then the username is valid and the switch can be enabled
          instagram = false;
          return true // return true to tell Yup the field is valid
        } else {
          instagram = true;
          return true // true removes error message
        }
      }
    )
    .test(
      'valid-twitter', "Twitter: may only contain alphanumeric characters or underscores", function (username){
        var twitterRegex = new RegExp(/^[A-Za-z0-9_]{1,15}$/);
        var twitterRes = twitterRegex.test(username)
        if (twitterRes) { // if res is true then the username is valid and the switch can be enabled
          twitter = false;
          return true // return true to tell Yup the field is valid
        } else {
          twitter = true;
          return true // true removes error message
        }
      }
    )
    .test(
      'valid-github', "GitHub: may only contain alphanumeric characters or single hyphens", function (username){
        var githubRegex = new RegExp(/^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i);
        var githubRes = githubRegex.test(username)
        if (githubRes) { // if res is true then the username is valid and the switch can be enabled
          github = false;
          return true // return true to tell Yup the field is valid
        } else {
          github = true;
          return true // true removes error message
        }
      }
    )
    .required("Required"),
  acceptTerms: Yup.boolean()
    .required("Required")
    .oneOf([true], "You must accept the terms and conditions."),
  switchGroup: Yup.array().required("At least one option must be selected"),
});

const initialValues = {
  firstName: "",
  email: "",
  username: "",
  acceptTerms: false, // added for our checkbox
  switchGroup: [], // array for switches
};

export default function Signup() {
  const [error, setError] = useState("");

  return (
    <Layout>
      <Head>
        <title>Signup - Notify.is</title>
      </Head>

      <div className="container-center">
        <Formik
          initialValues={initialValues}
          validationSchema={validationSchema}
          onSubmit={async (values, { setSubmitting }) => {
            const data = new URLSearchParams(values);
            const res = await axios
              .post("http://localhost:8080/api/signup", data)
              .then((response) => {
                Router.push("/thanks");
              })
              .catch((error) => {
                setError(error.message);
              });
            setSubmitting(false);
          }}
        >
          {({ touched, errors, isSubmitting }) => (
            <Form className="form">
              <h1 className="display-4 pb-3">Get notified</h1>

              <div className="form-label-group">
                <Field
                  type="text"
                  name="firstName"
                  id="firstName"
                  placeholder="First name"
                  className={`form-control ${
                    touched.firstName && errors.firstName
                      ? "is-invalid"
                      : null
                  }`}
                />
                <label htmlFor="firstname">First name</label>
                <small id="nameHelp" className="form-text text-muted">
                  Optional
                </small>
              </div>

              <div className="form-label-group">
                <Field
                  type="email"
                  name="email"
                  id="email"
                  placeholder="Email address"
                  className={`form-control ${
                    touched.email && errors.email ? "is-invalid" : null
                  }`}
                />
                <ErrorMessage
                  component="div"
                  name="email"
                  className="invalid-feedback"
                />
                <small id="emailHelp" className="form-text text-muted">
                  We'll never share your email with anyone else.
                </small>
                <label htmlFor="email">Email address</label>
              </div>

              <div className="form-label-group">
                <Field
                  type="text"
                  name="username"
                  id="username"
                  autoCorrect="off"
                  autoCapitalize="none"
                  placeholder="Username"
                  className={`form-control ${
                    touched.username && errors.username ? "is-invalid" : null
                  }`}
                />
                <ErrorMessage
                  component="div"
                  name="username"
                  className="invalid-feedback"
                />
                <small id="usernameHelp" className="form-text text-muted">
                  The unavailable username you want.
                </small>
                <label htmlFor="username">Username</label>
              </div>

              <div>
                <div className="custom-control custom-switch">
                  <Field
                    type="checkbox"
                    name="switchGroup"
                    id="instagram-switch"
                    value={instagram ? "" : "instagram"}
                    disabled={instagram}
                    className={`custom-control-input ${
                      touched.switchGroup && errors.switchGroup
                        ? "is-invalid"
                        : null
                    }`}
                  />
                  <label
                    className="custom-control-label"
                    htmlFor="instagram-switch"
                  >
                    Instagram
                  </label>
                </div>

                <div className="custom-control custom-switch">
                  <Field
                    type="checkbox"
                    name="switchGroup"
                    id="twitter-switch"
                    value={twitter ? "" : "twitter"}
                    disabled={twitter}
                    className={`custom-control-input ${
                      touched.switchGroup && errors.switchGroup
                        ? "is-invalid"
                        : null
                    }`}
                  />
                  <label
                    className="custom-control-label"
                    htmlFor="twitter-switch"
                  >
                    Twitter
                  </label>
                </div>

                <div className="custom-control custom-switch">
                  <Field
                    type="checkbox"
                    name="switchGroup"
                    id="github-switch"
                    value={github ? "" : "github"}
                    disabled={github}
                    className={`custom-control-input ${
                      touched.switchGroup && errors.switchGroup
                        ? "is-invalid"
                        : null
                    }`}
                  />
                  <label
                    className="custom-control-label"
                    htmlFor="github-switch"
                  >
                    GitHub
                  </label>
                  <ErrorMessage
                    component="div"
                    name="switchGroup"
                    className="invalid-feedback"
                  />
                </div>
                <small id="usernameHelp" className="form-text text-muted">
                  The service(s) we should check with.
                </small>
              </div>

              <div className="custom-control custom-checkbox pt-3 mb-1">
                <Field
                  type="checkbox"
                  name="acceptTerms"
                  id="acceptTerms"
                  className={`custom-control-input ${
                    touched.acceptTerms && errors.acceptTerms
                      ? "is-invalid"
                      : null
                  }`}
                />
                <label htmlFor="acceptTerms" className="custom-control-label">
                  By checking this box you agree to our:
                </label>
                <ErrorMessage
                  component="div"
                  name="acceptTerms"
                  className="invalid-feedback"
                />
              </div>
              <span className="grey termslabel">
                <Link href="/tos">
                  <a className="terms" target="_blank">
                    Terms of Use
                  </a>
                </Link>{" "}
                and{" "}
                <Link href="/privacy">
                  <a className="terms" target="_blank">
                    Privacy Policy
                  </a>
                </Link>
              </span>
              <Button
                className="btn-lg btn-primary btn-block mt-4"
                variant="primary"
                disabled={isSubmitting, error}
                type="submit"
              >
                {isSubmitting && (
                  <Spinner
                    as="span"
                    animation="grow"
                    size="lg"
                    role="status"
                    aria-hidden="true"
                  />
                )}
                {isSubmitting && <span> Submitting...</span>}
                {!isSubmitting && <span>Sign up</span>}
              </Button>
              {error ? <Error error={error} /> : null}
              <p className="mt-4 mb-3 text-muted text-center">
                &copy; Notify.is 2020
              </p>
            </Form>
          )}
        </Formik>
      </div>

      <style jsx>
        {`
          .display-4 {
            font-weight: 700;
          }

          .terms {
            text-decoration: underline;
          }
          .terms:hover {
            text-decoration: none;
          }
        `}
      </style>
    </Layout>
  );
}

检查 FieldArray 组件。它的渲染道具为来自 fieldArrays 的 adding/removing 值提供了一个 arrayHelper

我最终设法以不同于最初预期的方式完成了我想做的事情,但效果很好。

使用基于是否应禁用字段更改值的布尔变量,我为 Formik onSubmit prop 中的每个变量做了一个 if 语句,并在数组中的值的索引处更改了值应该是省略.

<Formik
          initialValues={initialValues}
          validationSchema={validationSchema}
          onSubmit={async (values, { setSubmitting }) => {

            // if the field was disabled then don't submit switch value
            if (instagram) {
              var i = values.switchGroup.indexOf("instagram");
              values.switchGroup[i] = null
            }
            if (twitter) {
              var i = values.switchGroup.indexOf("twitter");
              values.switchGroup[i] = null
            }
            if (github) {
              var i = values.switchGroup.indexOf("github");
              values.switchGroup[i] = null
            }

            const data = new URLSearchParams(values);
            const res = await axios
              .post("/api/signup", data)
              .then((response) => {
                Router.push("/thanks");
              })
              .catch((error) => {
                setError(error.message);
              });
            setSubmitting(false);
          }}
        >