Formik + yup 表单校验

MyForm.js:

import React, { useEffect, useState } from 'react';
import Form from 'react-bootstrap/Form';
import Button from 'react-bootstrap/Button';
import Alert from 'react-bootstrap/Alert';
import PropTypes from 'prop-types';
import { Formik } from 'formik';
import moment from 'moment';
import Api from '../../../api';
import { getValidationSchema, getFormFields } from './config';

function MyForm(props) {
  const [countrySelectOptions, setCountrySelectOptions] = useState([]);
  const [slaSelectOptions, setSlaSelectOptions] = useState([]);
  const [currencySelectOptions, setCurrencySelectOptions] = useState([]);
  const [tierSelectOptions, setTierSelectOptions] = useState([]);
  const [showSuccess, setShowSuccess] = useState(false);
  const [showError, setShowError] = useState(false);
  const [initialValues, setInitialValues] = useState({});
  const [isCountryLoading, setIsCountryLoading] = useState(true);
  const [isTierLoading, setIsTierLoading] = useState(true);

  const { addPriceMaster, clearErrors, data, user, addSuccess, addError } =
    props;

  let addInitialValues = {};
  let isTest = false;
  if (isTest) {
    addInitialValues = {
      usersCountry: 'US',
      serviceLevelAgreement: 'Next Business Day',
      costStopDate: moment(Date.now()).format('YYYY-MM-DD'),
      usersCurrency: 'USD',
      priceStartDate: moment(Date.now()).format('YYYY-MM-DD'),
      comments: '1',
      chargeTypeName: '1',
      priceStopDate: moment(Date.now()).format('YYYY-MM-DD'),
      price: 1.1,
      tier: 1,
      costStartDate: moment(Date.now()).format('YYYY-MM-DD'),
      cost: 1.1,
    };
  } else {
    addInitialValues = {
      usersCountry: '',
      serviceLevelAgreement: '',
      costStopDate: '',
      usersCurrency: '',
      priceStartDate: '',
      comments: '',
      chargeTypeName: '',
      priceStopDate: '',
      price: '',
      tier: '',
      costStartDate: '',
      cost: '',
    };
  }
  const defaultCountry = 'US';

  // set form field
  const handleFieldChange = (e, setFieldValue, field, type = 'text') => {
    let value;
    if (type === 'text') {
      value = e.target.value;
    } else if (type === 'date') {
      value = e.currentTarget.value;
    } else if (type === 'select') {
      value = e.value;
    } else if (type === 'dateForCountry') {
      value = e;
    }
    setFieldValue(field, value);
    if (field === 'usersCountry') {
      const tempCountry = data.find((item) => item.countryCode === e.value);
      if (tempCountry) {
        setFieldValue('usersCurrency', tempCountry.currencyISO);
      }
    }
  };

  // submit
  const handleSubmit = (values, formik) => {
    const { setSubmitting, resetForm } = formik;
    setSubmitting(true);
    const callback = () => {
      resetForm();
    };

    let tempValues = { ...values };
    tempValues.serviceChargeType = tempValues.chargeTypeName;
    delete tempValues.chargeTypeName;
    tempValues.costStopDate = moment(tempValues.costStopDate).format(
      'MM/DD/YYYY'
    );
    tempValues.priceStartDate = moment(tempValues.priceStartDate).format(
      'MM/DD/YYYY'
    );
    tempValues.priceStopDate = moment(tempValues.priceStopDate).format(
      'MM/DD/YYYY'
    );
    tempValues.costStartDate = moment(tempValues.costStartDate).format(
      'MM/DD/YYYY'
    );

    addPriceMaster(tempValues, user, callback);
  };

  // close alert
  const handleCloseAlert = (event, resetForm) => {
    resetForm();
    setShowSuccess(false);
    setShowError(false);
    clearErrors();
  };

  // country data, Currency data
  useEffect(() => {
    const formatCountryData = (data) => {
      const options = data.map((country) => {
        const { countryCode } = country;
        return {
          value: countryCode,
          label: countryCode,
        };
      });
      setCountrySelectOptions(options);
    };
    formatCountryData(data);
    if (Array.isArray(data) && data.length > 0) {
      setIsCountryLoading(false);
    } else {
      setIsCountryLoading(true);
    }
    const formatCurrencyData = (data) => {
      const options = data.map((country) => {
        const { value, label } = country;
        return {
          value,
          label,
        };
      });
      setCurrencySelectOptions(options);
    };
    let currencyOptionArr = data.map((item) => {
      return {
        value: item.currencyISO,
        label: item.currencyISO,
      };
    });
    formatCurrencyData(currencyOptionArr);
  }, [data]);

  //SLA data, Tier data
  useEffect(() => {
    const formatTierData = (data) => {
      const options = data.map((country) => {
        const { value, label } = country;
        return {
          value,
          label,
        };
      });
      setTierSelectOptions(options);
    };
    Api.light.priceMasterTierList().then((res) => {
      if (Array.isArray(res.data.content)) {
        let tierOptionArr = [];
        tierOptionArr = res.data.content.map((item) => item.serviceTierCode);
        tierOptionArr = [...new Set(tierOptionArr)];
        tierOptionArr = tierOptionArr.map((item) => {
          return {
            value: item,
            label: item,
          };
        });
        formatTierData(tierOptionArr);
        setIsTierLoading(false);
      }
    });

    const formatSlaData = (data) => {
      const options = data.map((country) => {
        const { value, label } = country;
        return {
          value,
          label,
        };
      });
      setSlaSelectOptions(options);
    };

    let slaOptionArr = [
      { label: 'Next Business Day', value: 'Next Business Day' },
      { label: 'Same Business Day', value: 'sameBusinessDay' },
      { label: 'Depot CCI delivery', value: 'Depot/CCI delivery' },
      { label: 'ADP', value: 'ADP' },
      { label: 'ADP ONE', value: 'ADP ONE' },
      { label: 'KYD', value: 'KYD' },
      { label: 'SBTY', value: 'sybt' },
      { label: 'Premier Support 24x7 365', value: 'premiere365' },
      { label: 'Premium Care', value: 'premiumCare' },
    ];
    formatSlaData(slaOptionArr);
  }, []);

  // success
  useEffect(() => {
    if (addSuccess.isSuccess) {
      setShowSuccess(true);
      const timer = setTimeout(() => {
        setShowSuccess(false);
        clearErrors();
        clearTimeout(timer);
      }, 2000);
    }
  }, [addSuccess.isSuccess]);

  // error
  useEffect(() => {
    if (addError.isError) {
      setShowError(true);
      const timer = setTimeout(() => {
        setShowError(false);
        clearErrors();
        clearTimeout(timer);
      }, 2000);
    }
  }, [addError.isError]);

  return (
    <Formik
      initialValues={{
        ...initialValues,
        ...addInitialValues,
      }}
      validationSchema={getValidationSchema()}
      onSubmit={handleSubmit}
    >
      {(formik) => {
        //console.log(666, formik.values, formik.touched, formik.errors)
        const { resetForm, isSubmitting } = formik;
        return (
          <Form noValidate onSubmit={formik.handleSubmit}>
            {getFormFields({
              formik,
              defaultCountry,
              countrySelectOptions,
              slaSelectOptions,
              currencySelectOptions,
              tierSelectOptions,
              isCountryLoading,
              isTierLoading,
              handleFieldChange,
            })}
            <Button
              type="submit"
              className="table-button-right "
              disabled={isSubmitting}
            >
              ADD
            </Button>

            <Alert
              variant="success"
              dismissible={true}
              show={showSuccess}
              onClose={(event) => handleCloseAlert(event, resetForm)}
              role="alert"
              className="user-form-alert"
            >
              <strong>Success: </strong>
              {addSuccess.msg}
            </Alert>

            <Alert
              variant="danger"
              dismissible={true}
              show={showError}
              onClose={(event) => handleCloseAlert(event, resetForm)}
              role="alert"
              className="user-form-alert"
            >
              <strong>Failure: </strong> {addError.msg}
            </Alert>
          </Form>
        );
      }}
    </Formik>
  );
}

MyForm.propTypes = {
  user: PropTypes.object,
  addPriceMaster: PropTypes.func.isRequired,
  data: PropTypes.array,
  getCountriesByPage: PropTypes.func,
  addError: PropTypes.object,
  addSuccess: PropTypes.object,
  clearErrors: PropTypes.func,
};

export default MyForm;

config.js:

import React from 'react';
import * as yup from 'yup';
import Form from 'react-bootstrap/Form';
import { Col } from 'react-bootstrap';
import InternationalCalendarField from '../../../components/Fields/InternationalDateField';
import CustomSelect from '../../../components/Select/CustomSelect';
import moment from 'moment';
import {
  dateTestAfterToday,
  dateTestAfterOtherDay,
  dateTestBeforeOtherDay,
  greaterThanZero,
} from '../../../utils/tools';

// Form verification field
const getValidationSchema = () => {
  const requireMsg = 'This is a required field';
  const dateTestAfterTodayMsg = 'Please select a date after today';
  const dateTestAfterOtherDayMsg = 'Please select a date after the start date';
  const dateTestBeforeOtherDayMsg = 'Please select a date before the end date';
  const validationSchema = yup.object({
    usersCountry: yup.string().trim().required(requireMsg),
    serviceLevelAgreement: yup.string().trim().required(requireMsg),
    costStopDate: yup
      .string()
      .trim()
      .required(requireMsg)
      .test('costStopDate', dateTestAfterTodayMsg, dateTestAfterToday)
      .test(
        'costStopDate',
        dateTestAfterOtherDayMsg,
        dateTestAfterOtherDay('costStartDate')
      ),
    usersCurrency: yup.string().trim().required(requireMsg),
    priceStartDate: yup.string().trim().required(requireMsg).test(
      'priceStartDate',
      dateTestBeforeOtherDayMsg,
      dateTestBeforeOtherDay('priceStopDate')
    ),
    comments: yup.string().required(requireMsg),
    chargeTypeName: yup.string().trim().required(requireMsg),
    priceStopDate: yup
      .string()
      .trim()
      .required(requireMsg)
      .test('priceStopDate', dateTestAfterTodayMsg, dateTestAfterToday)
      .test(
        'priceStopDate',
        dateTestAfterOtherDayMsg,
        dateTestAfterOtherDay('priceStartDate')
      ),
    price: yup.number().required(requireMsg).test('price', ' Please enter a number greater than 0', greaterThanZero),
    tier: yup.string().trim().required(requireMsg),
    costStartDate: yup
      .string()
      .trim()
      .required(requireMsg)
      .test(
        'costStartDate',
        dateTestBeforeOtherDayMsg,
        dateTestBeforeOtherDay('costStopDate')
      ),
    cost: yup.number().required(requireMsg).test('price', ' Please enter a number greater than 0', greaterThanZero),
  });

  return validationSchema;
};

// form field
const getFormFields = (props) => {
  const {
    formik,
    defaultCountry,
    countrySelectOptions,
    slaSelectOptions,
    currencySelectOptions,
    tierSelectOptions,
    isCountryLoading,
    isTierLoading,
    handleFieldChange,
  } = props;
  const { setFieldValue, resetForm, values, touched, errors, isSubmitting } =
    formik;
  return (
    <>
      <Form.Row>
        <Form.Group as={Col} md={4} controlId="usersCountry">
          <Form.Label className="required">Country</Form.Label>
          <Form.Control
            required
            as={CustomSelect}
            isLoading={isCountryLoading}
            id="usersCountry"
            {...formik.getFieldProps('usersCountry')}
            options={countrySelectOptions}
            onChange={(value) =>
              handleFieldChange(value, setFieldValue, 'usersCountry', 'select')
            }
            isInvalid={touched.usersCurrency && errors.usersCountry}
          />
          <Form.Control.Feedback
            className="select-invalid-feedback"
            type="invalid"
          >
            {values.usersCurrency
              ? ''
              : touched.usersCurrency && errors.usersCountry}
          </Form.Control.Feedback>
        </Form.Group>
        <Form.Group as={Col} md={4} controlId="serviceLevelAgreement">
          <Form.Label className="required">SLA</Form.Label>
          <Form.Control
            required
            as={CustomSelect}
            id="serviceLevelAgreement"
            {...formik.getFieldProps('serviceLevelAgreement')}
            onChange={(value) =>
              handleFieldChange(
                value,
                setFieldValue,
                'serviceLevelAgreement',
                'select'
              )
            }
            options={slaSelectOptions}
            isInvalid={
              touched.serviceLevelAgreement && errors.serviceLevelAgreement
            }
          />
          <Form.Control.Feedback
            className="select-invalid-feedback"
            type="invalid"
          >
            {touched.serviceLevelAgreement && errors.serviceLevelAgreement}
          </Form.Control.Feedback>
        </Form.Group>
        <Form.Group as={Col} md={4} controlId="costStopDate">
          <Form.Label className="required">Cost Stop Date</Form.Label>
          <Form.Control
            required
            as={InternationalCalendarField}
            id="costStopDate"
            {...formik.getFieldProps('costStopDate')}
            country={values.usersCountry ? values.usersCountry : defaultCountry}
            date={values.costStopDate}
            onCalendarChange={(value) => {
              handleFieldChange(
                value,
                setFieldValue,
                'costStopDate',
                'dateForCountry'
              );
            }}
            storedDateFormat="yyyy-MM-dd"
            errorMsg={false}
          />
          <Form.Control.Feedback
            className="select-invalid-feedback"
            type="invalid"
          >
            {(touched.costStopDate || values.costStopDate) && errors.costStopDate}
          </Form.Control.Feedback>
        </Form.Group>
      </Form.Row>

      <Form.Row>
        <Form.Group as={Col} controlId="usersCurrency">
          <Form.Label className="required">Currency</Form.Label>
          <Form.Control
            required
            as={CustomSelect}
            isLoading={isCountryLoading}
            value={values.usersCurrency}
            isDisabled={true}
            options={currencySelectOptions}
            id="usersCurrency"
            {...formik.getFieldProps('usersCurrency')}
            onChange={(value) =>
              handleFieldChange(value, setFieldValue, 'usersCurrency', 'select')
            }
            isInvalid={touched.usersCurrency && errors.usersCurrency}
          />
          <Form.Control.Feedback
            className="select-invalid-feedback"
            type="invalid"
          >
            {touched.usersCurrency && errors.usersCurrency}
          </Form.Control.Feedback>
        </Form.Group>
        <Form.Group as={Col} controlId="priceStartDate">
          <Form.Label className="required">Price Start Date</Form.Label>
          <Form.Control
            required
            placeholder="Select Date"
            as={InternationalCalendarField}
            id="priceStartDate"
            {...formik.getFieldProps('priceStartDate')}
            country={values.usersCountry ? values.usersCountry : defaultCountry}
            date={values.priceStartDate}
            onCalendarChange={(value) => {
              handleFieldChange(
                value,
                setFieldValue,
                'priceStartDate',
                'dateForCountry'
              );
            }}
            storedDateFormat="yyyy-MM-dd"
            errorMsg={false}
          />

          <Form.Control.Feedback
            className="select-invalid-feedback"
            type="invalid"
          >
            {(touched.priceStartDate || values.priceStartDate) && errors.priceStartDate}
          </Form.Control.Feedback>
        </Form.Group>
        <Form.Group as={Col} controlId="comments">
          <Form.Label className="required">Comments</Form.Label>
          <Form.Control
            required
            id="comments"
            type="text"
            {...formik.getFieldProps('comments')}
            placeholder="Enter"
            isInvalid={touched.comments && errors.comments}
          />
          <Form.Control.Feedback
            className="select-invalid-feedback"
            type="invalid"
          >
            {touched.comments && errors.comments}
          </Form.Control.Feedback>
        </Form.Group>
      </Form.Row>

      <Form.Row>
        <Form.Group as={Col} controlId="chargeTypeName">
          <Form.Label className="required">Charge Type Name</Form.Label>
          <Form.Control
            required
            id="chargeTypeName"
            {...formik.getFieldProps('chargeTypeName')}
            type="text"
            placeholder="Enter"
            isInvalid={touched.chargeTypeName && errors.chargeTypeName}
          />
          <Form.Control.Feedback
            className="select-invalid-feedback"
            type="invalid"
          >
            {touched.chargeTypeName && errors.chargeTypeName}
          </Form.Control.Feedback>
        </Form.Group>
        <Form.Group as={Col} controlId="priceStopDate">
          <Form.Label className="required">Price Stop Date</Form.Label>
          <Form.Control
            required
            as={InternationalCalendarField}
            country={values.usersCountry ? values.usersCountry : defaultCountry}
            date={values.priceStopDate}
            onCalendarChange={(value) => {
              handleFieldChange(
                value,
                setFieldValue,
                'priceStopDate',
                'dateForCountry'
              );
            }}
            id="priceStopDate"
            {...formik.getFieldProps('priceStopDate')}
            errorMsg={false}
          />

          <Form.Control.Feedback
            className="select-invalid-feedback"
            type="invalid"
          >
            {(touched.priceStopDate || values.priceStopDate) && errors.priceStopDate}
          </Form.Control.Feedback>
        </Form.Group>
        <Form.Group as={Col} controlId="price">
          <Form.Label className="required">Price</Form.Label>
          <Form.Control
            required
            type="number"
            id="price"
            {...formik.getFieldProps('price')}
            placeholder="Enter"
            isInvalid={touched.price && errors.price}
          />
          <Form.Control.Feedback
            className="select-invalid-feedback"
            type="invalid"
          >
            {touched.price && errors.price}
          </Form.Control.Feedback>
        </Form.Group>
      </Form.Row>

      <Form.Row>
        <Form.Group as={Col} controlId="tier">
          <Form.Label className="required">Tier</Form.Label>
          <Form.Control
            required
            as={CustomSelect}
            isLoading={isTierLoading}
            options={tierSelectOptions}
            id="tier"
            {...formik.getFieldProps('tier')}
            onChange={(value) =>
              handleFieldChange(value, setFieldValue, 'tier', 'select')
            }
            isInvalid={touched.tier && errors.tier}
          />
          <Form.Control.Feedback
            className="select-invalid-feedback"
            type="invalid"
          >
            {touched.tier && errors.tier}
          </Form.Control.Feedback>
        </Form.Group>
        <Form.Group as={Col} controlId="costStartDate">
          <Form.Label className="required">Cost Start Date</Form.Label>
          <Form.Control
            required
            type="date"
            as={InternationalCalendarField}
            country={values.usersCountry ? values.usersCountry : defaultCountry}
            date={values.costStartDate}
            onCalendarChange={(value) => {
              handleFieldChange(
                value,
                setFieldValue,
                'costStartDate',
                'dateForCountry'
              );
            }}
            id="costStartDate"
            {...formik.getFieldProps('costStartDate')}
            errorMsg={false}
          />
          <Form.Control.Feedback
            className="select-invalid-feedback"
            type="invalid"
          >
            {(touched.costStartDate || values.costStartDate) && errors.costStartDate}
          </Form.Control.Feedback>
        </Form.Group>
        <Form.Group as={Col} controlId="cost">
          <Form.Label className="required">Cost</Form.Label>
          <Form.Control
            required
            type="number"
            placeholder="Enter"
            isInvalid={touched.cost && errors.cost}
            id="cost"
            {...formik.getFieldProps('cost')}
          />
          <Form.Control.Feedback
            className="select-invalid-feedback"
            type="invalid"
          >
            {touched.cost && errors.cost}
          </Form.Control.Feedback>
        </Form.Group>
      </Form.Row>
    </>
  );
};

// Table column
const getColumns = () => {
  return [
    {
      dataField: 'id',
      text: 'ID',
      hidden: true,
    },
    {
      dataField: 'usersCountry',
      text: 'Country',
    },
    {
      dataField: 'usersCurrency',
      text: 'Currency',
    },
    {
      dataField: 'serviceChargeType',
      text: 'Charge Type Name',
    },
    {
      dataField: 'tier',
      text: 'Tier',
    },
    {
      dataField: 'serviceLevelAgreement',
      text: 'SLA',
    },
    {
      dataField: 'priceStartDate',
      text: 'Price Start Date',
      formatter: (text) => {
        return moment(text).format('MM/DD/YYYY');
      },
    },
    {
      dataField: 'priceStopDate',
      text: 'Price Stop Date',
      formatter: (text) => {
        return moment(text).format('MM/DD/YYYY');
      },
    },
    {
      dataField: 'costStartDate',
      text: 'Cost Start Date',
      formatter: (text) => {
        return moment(text).format('MM/DD/YYYY');
      },
    },
    {
      dataField: 'costStopDate',
      text: 'Cost Stop Date',
      formatter: (text) => {
        return moment(text).format('MM/DD/YYYY');
      },
    },
    {
      dataField: 'comments',
      text: 'Comments',
    },
    {
      dataField: 'price',
      text: 'Price',
    },
    {
      dataField: 'cost',
      text: 'Cost',
    },
  ];
};

export { getValidationSchema, getFormFields, getColumns };

tools.js:

import moment from 'moment'

//get userinfo
const getUserInfo = () => {
  const tempLocalStorageUserInfo = localStorage.getItem('moto')
  const { access_token, token_type } = tempLocalStorageUserInfo
    ? JSON.parse(tempLocalStorageUserInfo)
    : {}
  return {
    token: `${token_type} ${access_token}`
  }
}

//after today
const dateTestAfterToday = function (value) {
  const now = moment(Date.now()).format('YYYY-MM-DD')
  if (moment(value).valueOf() <= moment(now).valueOf()) {
    return false
  } else {
    return true
  }
}

//after other day
const dateTestAfterOtherDay = function (field) {
  return function (value, context) {
    if (context.parent[field] && moment(value).valueOf() <= moment(context.parent[field]).valueOf()) {
      return false
    } else {
      return true
    }
  }
}

//before other day
const dateTestBeforeOtherDay = function (field) {
  return function (value, context) {
    if (context.parent[field] && moment(value).valueOf() >= moment(context.parent[field]).valueOf()) {
      return false
    } else {
      return true
    }
  }
}

// Greater than 0 
const greaterThanZero = (value) => {
  return value > 0
}

export {
  getUserInfo,
  dateTestAfterToday,
  dateTestAfterOtherDay,
  dateTestBeforeOtherDay,
  greaterThanZero,
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
React中实现多个表单校验可以通过以下步骤进行操作: 1. 创建表单组件:首先,创建一个表单组件,可以使用`<form>`元素来包裹表单的各个输入字段。 2. 创建表单字段组件:为每个需要校验表单字段创建一个独立的组件。这些组件可以是自定义组件,也可以是HTML中的原生表单元素(如`<input>`、`<select>`等)。 3. 设置表单字段的状态:为每个表单字段组件设置相应的状态,用于存储用户输入的值和校验结果。可以使用React的`useState`钩子来管理状态。 4. 编写校验规则:为每个表单字段定义校验规则,例如必填字段、长度限制、格式验证等。可以使用正则表达式或其他验证库来完成校验。 5. 执行校验逻辑:在表单提交或字段失去焦点等事件中,触发校验逻辑。遍历所有的表单字段状态,根据校验规则对各个字段的值进行验证,并更新相应的校验结果状态。 6. 显示校验结果:根据校验结果状态,显示相应的提示信息或错误样式。可以使用条件渲染来控制提示信息的显示与隐藏。 7. 提交表单:在表单提交事件中,检查所有字段的校验结果。如果所有字段都通过了校验,则可以继续执行提交操作;否则,阻止表单的默认提交行为,并提示用户进行必要的修正。 以上是一种简单的实现方式,你可以根据具体的业务需求进行调整和扩展。同时,可以使用一些第三方库来简化表单校验的过程,例如`formik`、`yup`等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

徐同保

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值