有效字段更改后,Formik 调度 Redux 操作

Formik dispatch Redux action after valid field change

我构建了这个使用 Formik 表单的沙盒 React 应用程序。

如果电子邮件字段验证触发且有效,我想调度 Redux 操作。 我想分派操作以从用户电子邮件中进行一些查找。此操作将更新 redux 状态并填充我表单上的其他字段。

因此,如果电子邮件字段有效,则会发生此调度。其他字段可能无效,我还没有提交表单。

我该怎么做?我找不到关于此的任何文档!

https://codesandbox.io/s/x32yoo242q

谢谢!

您可以创建一个可重复使用的自定义 component 调用对 input 更新的辅助操作。在这种情况下,如果输入有效且具有值,它将调度 action(redux 操作),如果无效,and/or 可选择调度辅助操作。

更新:利用componentDidUpdate。它不那么冗长,并且需要较少的手动字段级处理。此外,你还应该 debounce 避免大量 redux 操作触发的功能。

工作示例(电子邮件)

工作示例 (Material UI Select):


components/Input(自定义组件--componentDidUpdate控制是否调用validateField

import React, { Fragment, PureComponent } from "react";

class Input extends PureComponent {
  componentDidUpdate = prevProps => {
    const { errors, value } = this.props;
    if (errors !== prevProps.errors || value !== prevProps.value) {
      this.props.validateField({ errors, value });
    }
  };

  render = () => {
    const { errors, label, name, touched, validateField, ...rest } = this.props;
    return (
      <Fragment>
        <label htmlFor={name} style={{ display: "block" }}>
          {label}
        </label>
        <input {...rest} name={name} />
        {errors && touched && (
          <div style={{ color: "red", marginTop: ".5rem" }}>{errors}</div>
        )}
      </Fragment>
    );
  };
}

export default Input;

containers/FormvalidateField 控制 redux 动作)

import debounce from "lodash/debounce";
import React from "react";
import { withFormik } from "formik";
import Input from "../../components/Input";
import DisplayFormikState from "../../components/DisplayFormState";
import { resetMessage, setMessage } from "../../actions/message";
import store from "../../store";
import * as Yup from "yup";

const formikEnhancer = withFormik({
  validationSchema: Yup.object().shape({
    email: Yup.string()
      .email("Invalid email address")
      .required("Email is required!")
  }),
  mapPropsToValues: props => ({
    email: ""
  }),
  handleSubmit: (values, { setSubmitting }) => {
    const payload = {
      ...values
    };

    setTimeout(() => {
      alert(JSON.stringify(payload, null, 2));
      setSubmitting(false);
    }, 1000);
  },
  displayName: "MyForm"
});

const handleFormReset = handleReset => {
  store.dispatch(resetMessage());
  handleReset();
};

const validateField = debounce(
  ({ errors, value }) =>
    !errors && value
      ? store.dispatch(setMessage())
      : store.dispatch(resetMessage()),
  500
);

const MyForm = props => {
  const {
    values,
    touched,
    dirty,
    errors,
    handleBlur,
    handleChange,
    handleReset,
    handleSubmit,
    isSubmitting
  } = props;

  return (
    <form onSubmit={handleSubmit}>
      <Input
        name="email"
        label="Email"
        type="email"
        placeholder="Enter an email address."
        errors={errors.email}
        value={values.email}
        touched={touched.email}
        onChange={handleChange}
        onBlur={handleBlur}
        validateField={validateField}
      />
      <button
        type="button"
        className="outline"
        onClick={() => handleFormReset(handleReset)}
        disabled={!dirty || isSubmitting}
      >
        Reset
      </button>
      <button type="submit" disabled={isSubmitting}>
        Submit
      </button>

      <DisplayFormikState {...props} />
    </form>
  );
};

export default formikEnhancer(MyForm);

实现您想要的效果的最简单直接的方法是使用电子邮件输入的 onBlur 处理程序。您可以通过执行以下操作来扩展默认处理程序:

<input
  id="email"
  placeholder="Enter your email"
  type="email"
  value={values.email}
  onChange={handleChange}
  onBlur={e => {
    handleBlur(e);
    if (!errors.email) {
      console.log("dispatch: ", e.currentTarget.value);
    }
  }}
/>

通过首先调用 Formik 的 handleBlur,您可以保留默认的验证行为,同时随后添加您自己的验证行为。您的表单正在验证 onChange 以及 onBlur 所以 errors.email 应该始终准确表示电子邮件输入的有效性,如果电子邮件在模糊状态下有效,我们可以使用它来发送(在我的示例中,我只是将一些内容记录到控制台以进行说明)。查看 沙盒 以查看它的实际效果: