如何将 react-intl-tel-input 与 formik 集成?

Posted

技术标签:

【中文标题】如何将 react-intl-tel-input 与 formik 集成?【英文标题】:How to integrate react-intl-tel-input with 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 和验证模式?

提前谢谢...

【问题讨论】:

【参考方案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);
  
/>

【讨论】:

以上是关于如何将 react-intl-tel-input 与 formik 集成?的主要内容,如果未能解决你的问题,请参考以下文章

如何将CString转换成wstring

如何将Ios文件上传到

Qt如何将文字变成图片?

如何将Bitmap保存为本地图片文件?

在MATLAB中如何将图导出

ASP如何将SQLSERVER数据导出到DBF(VF)