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

How to integrate react-intl-tel-input with formik?

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

这是我的 phone 数字组件:

<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 和验证模式?

提前致谢...

这不是最佳解决方案,但将 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 等验证器来检查 phone 号码不是 "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]);
};

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

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;

如果您使用的是 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);
  }}
/>