【问题标题】:How to integrate react-intl-tel-input with formik?如何将 react-intl-tel-input 与 formik 集成?
【发布时间】:2019-06-24 22:45:14
【问题描述】:

我正在使用 Formik 在我的 ReactJs 应用程序中处理表单,我想使用 react-intl-tel-input 来处理电话号码,但是我无法将 handleChange、handleBlur 和验证与 Formik 集成。现在我正在使用我的表单状态来保存电话号码及其验证状态,但这会通过重新渲染我的其他字段而导致 Formik 出现问题。

这是我的电话号码组件:

<IntlTelInput
  fieldId="userPhoneNumber"
  fieldName="userPhoneNumber"
  value={values.userPhoneNumber}
  preferredCountries={preferredMobileCountries}
  css={['intl-tel-input', `form-control ${(!validPhoneNumber) ? 'is-invalid' : ''}`]}
  style={{display: 'block',width: '100%'}}
  format
  onPhoneNumberChange={this.handlePhoneChange}
/>
{!validPhoneNumber && <div className="invalid-feedback">Invalid phone number</div>}

实现此目的的正确方法是什么?我的意思是使用自定义组件但能够使用 Formik 的 handleChange、handleBlur 和验证模式?

提前谢谢...

【问题讨论】:

    标签: reactjs formik intl-tel-input


    【解决方案1】:

    这不是最佳解决方案,而是将 IntlTelInput 链接回 formik 的 setFieldTouched 和 setFieldValue。

    // @flow
    
    import React, {Component, Fragment} from 'react';
    import {ErrorMessage, Field} from 'formik';
    import IntlTelInput from 'react-intl-tel-input';
    
    export default class MobileField extends Component {
      formatPhoneNumberOutput(
        isValid: boolean,
        newNumber: string,
        countryData: Object,
        fullNumber: string,
        isExtension: boolean
      ) {
        if (isValid && fullNumber) {
          return fullNumber.replace(/(\s|-)/g, '');
        }
        return 'invalid_phone_number'; // caught by validator
      }
    
      render() {
        return (
          <Field
            name={name}
            render={({field, form: {errors, isSubmitting, touched, setFieldTouched, setFieldValue}}) => {
              return (
                <Fragment>
                  <IntlTelInput
                    defaultCountry="fr"
                    defaultValue={field.value}
                    disabled={isSubmitting}
                    fieldId={name}
                    fieldName={name}
                    onPhoneNumberBlur={() => {
                      setFieldTouched(name, true);
                    }}
                    onPhoneNumberChange={(...args) => {
                      setFieldValue(name, this.formatPhoneNumberOutput(...args));
                    }}
                    preferredCountries={['fr', 'gb', 'es', 'be', 'de']}
                  />
                  <ErrorMessage name={name} render={msg => <p>{msg}</p>} />
                </Fragment>
              );
            }}
          />
        );
      }
    }
    

    使用 validate.js 等验证器检查电话号码是否不是“invalid_phone_number”

    // @flow
    
    import _mapValues from 'lodash/mapValues';
    import validate from 'validate.js';
    
    export type Values = {
        mobile: string,
        landline: string
    };
    
    export default (values: Values) => {
        const options = {
            fullMessages: false
        };
      const validation: {[key: string]: string[]} = validate(
          values,
          {
              mobile: {
                  presence: {message: 'Please add a mobile phone number'},
                  format: {
                      pattern: '^((?!invalid_phone_number).)*$', // is not invalid_phone_number
                      message: 'This phone number looks like being invalid'
                  }
            },
            landline: {}
        },
        options
        );
        return _mapValues(validation, messages => messages[0]);
    };
    

    【讨论】:

    • 您好@gasp 感谢您的回复,但是不完全了解如何将其与 validate.js 集成?我的意思是在哪里可以指定验证手机的规则?
    【解决方案2】:

    如果有人希望集成到功能组件(而不是基于类的组件)中,这可能会为您节省一些时间! :)

    import React, { useState } from 'react';
    import PropTypes from 'prop-types';
    import IntlTelInput from 'react-intl-tel-input';
    import { Field } from 'formik';
    import 'react-intl-tel-input/dist/main.css';
    
    const TelephoneInput = ({ name, ...props }) => {
    
      const [telephoneValid, setTelephoneValid] = useState(true);
      const setValidity = valid => {
        setTelephoneValid(valid);
      };
      // process number into string with area code for submission
      const processNumber = (isValid, phone, country) => {
        return `+${country.dialCode} ${phone}`;
      };
    
      return (
        <>
          <Field name={name}>
            {(
              { field: { value },
              form: { isSubmitting, setFieldTouched, setFieldValue } }) =>
                <IntlTelInput
                  {...props}
                  containerClassName="intl-tel-input"
                  inputClassName={telephoneValid ? 'valid' : 'invalid'}
                  label="telephone"
                  defaultValue={value}
                  disabled={isSubmitting}
                  fieldId={name}
                  fieldName={name}
                  onPhoneNumberBlur={(isValid) => {
                    setFieldTouched(name, true);
                    setValidity(isValid);
                  }}
                  onPhoneNumberChange={(isValid, phone, country) => {
                    setFieldValue(name, processNumber(isValid, phone, country));
                  }}
                />
            }
          </Field>
        </>
      );
    };
    
    TelephoneInput.propTypes = {
      name: PropTypes.string.isRequired,
    };
    export default TelephoneInput;
    

    【讨论】:

      【解决方案3】:

      如果你使用的是 useFormik 钩子

      import IntlTelInput from "react-intl-tel-input";
      
      
      <IntlTelInput
        inputClassName="tel-number"
        fieldId="number"
        fieldName="number"
        onPhoneNumberChange={(
          isValid,
          value,
          selectedCountryData,
          fullNumber
        ) => {
          formik.handleChange("number")(fullNumber);
        }}
      />
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-10-19
        • 1970-01-01
        • 2022-06-17
        • 2016-01-20
        • 1970-01-01
        • 1970-01-01
        • 2015-06-03
        • 2019-08-22
        相关资源
        最近更新 更多