SoFunction
Updated on 2025-03-03

Byte encapsulation React component mobile phone number automatic verification format FormItem

Situation Background

  • Among the old projects developed by many people, many places have written requirements for verifying mobile phone formats, and the codes have their own advantages and a hundred flowers bloom.
  • Implementation: Some are written in the public component library, some are developed separately for local component support, some are written directly without reuse, and some are withdrawn from regularity and then introduced to utils.
  • Regular: Regular verification has its own advantages, such as /^\d{11}/, /1\d10/, /1[2−9]\d9/, /^1\d{10}/, /^1[2-9]\d{9}/, /1\d10/, /1[2−9]\d9/, /^1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\d{8}$/, etc.
  • Length limit: some places limit maxLength=11, while others do not limit
  • Input format: Some places meet the 334 format (181 2222 3333) mobile phone number input, while others only allow pure numbers to be entered

Target Target

  • Implement an easy-to-use mobile phone number public component
  • Use looser regular verification and agree with the backend
  • No longer limiting the input length, but an error message will be reported
  • Supports format input of 334 and automatically removes all spaces
  • Write parameter descriptions for easy development and use
  • Stay as flexible as possible and apply to more scenarios

Action

import type {
  FormItemProps,
  InputProps,
  RulesProps,
} from '@arco-design/web-react';
import { Form, Input } from '@arco-design/web-react';
import { usePersistCallback } from '@byted/hooks';
import type { ReactNode } from 'react';
import { useMemo } from 'react';
export type VerifyInputProps = {
  /** 🔥 Bind attributes */
  field: string;
  /** 🔥 Show tag text */
  label: string;
  /** Whether the required * number is displayed in front of the label */
  labelRequired?: boolean;
  /** 🔥 Whether rules are required to add the required verification (no labelRequired=true is required when true) */
  phoneRequired?: boolean;
  /** Other rules except for checking the format of mobile phone number, regular inspection is added by default/^1[2-9]\d{9}$/ */
  rules?: RulesProps<any>[];
  /** Show prompt text */
  placeholder?: string;
  /** Whether to disable input */
  disabled?: boolean;
  /** phone input box onChange event */
  onChange?: InputProps['onChange'];
  /** Other properties of FormItem */
  formItemProps?: FormItemProps;
  /** Input other properties */
  inputProps?: InputProps;
};
/** Mobile phone number form (with ) */
export const VerifyPhoneInput = (props: VerifyInputProps) => {
  const {
    field,
    label,
    placeholder,
    rules = [],
    labelRequired = false,
    phoneRequired = false,
    disabled,
    onChange,
    formItemProps,
    inputProps,
  } = props;
  const resultRules = useMemo(() => {
    const arr = [
      {
        validator(val: string | undefined, cb: (error?: ReactNode) => void) {
          const realVal = (`${val}` as any).replaceAll(' ', '');
          if (!val || /^1[2-9]\d{9}$/.test(realVal)) {
            cb();
          } else {
            cb(`Please enter the correct one${label}`);
          }
        },
      },
      ...rules,
    ];
    if (phoneRequired) {
      ({
        validator(val: string | undefined, cb: (error?: ReactNode) => void) {
          if (!val) {
            cb(`Please enter${label}`);
          } else {
            cb();
          }
        },
      });
    }
    return arr;
  }, [rules, phoneRequired, label]);
  const normalize = usePersistCallback((val: string | undefined) => {
    if (val) {
      const realVal = (`${val}` as any).replaceAll(' ', '');
      if (val !== realVal) {
        return realVal;
      }
    }
    return val;
  });
  const resultInputProps = {
    disabled,
    onChange,
    allowClear: true,
    placeholder: placeholder || `Please enter${label}`,
    ...inputProps,
  };
  return (
    <
      required={labelRequired || phoneRequired}
      field={field}
      label={label}
      formatter={normalize}
      rules={resultRules}
      {...formItemProps}
    >
      <Input {...resultInputProps} />
    </>
  );
};
  • Define the parameter type VerifyInputProps, sort and explain the properties by frequency of use
  • Move the required fill out of the rules and turns it into the phoneRequired parameter. The error message is also automatically spliced ​​according to the label. Please enter the correct ${label}. The package is complicated and the exposure is simple.
  • Placeholder is automatically spliced ​​according to label by default (please enter ${label}) to improve ease of use
  • Converge other properties of FormItem into formItemProps to facilitate development students to expand and improve universality
  • The default allowClear=true can be overridden by inputProps
  • Automatically remove all spaces through formatter, supporting 334 format
  • Converge other Input properties into inputProps to facilitate development students to expand and improve universality
  • Expose rules, support custom remote verification and other rules
  • Expose commonly used disabled and onChange to facilitate use on the outermost layer

Results

  • It has been put into use, the test meets expectations, and is provided to other colleagues for use, and will continue to be improved in the future

Review

  • Question 1: After using normalize to remove spaces, the error verification below input did not re-trigger, resulting in the input box data being correct, and the error prompts still exist.
    • Solution: The first solution passes form in, and re-triggers verification through form?.validate(field) after formatter; the second solution changes rules to validator implementation method to manually remove spaces. There is no desire to introduce more parameters, and the second one is finally adopted.
  • Question 2: How to define regular formats to balance correctness and universality
    • Solution: Negotiate with the backend to use the strictest verification format applicable to all currently visible scenarios/^1[2-9]\d{9}$/
  • Question 3: Old code governance
    • Solution: Change all codes related to mobile phone numbers at one time, requiring testing intervention to bring a lot of regression testing time, and the benefits are very small. Therefore, if new requirements use this component, the cost of changing the old requirements is even smaller.
  • Question 4: Can you enrich it?
    • Supports 151****2222 display and editing without modification and verification, ensuring the privacy of mobile phone number
  • Question 5: VerifyPhoneInput is actually a FormItem component, and the original API and FormItem are very different. Will it bring mental burden to the user?
    • solve:
import type { FormItemProps, InputProps } from '@arco-design/web-react';
import { Form, Input } from '@arco-design/web-react';
import { usePersistCallback } from '@byted/hooks';
import type { ReactNode } from 'react';
import { useMemo } from 'react';
const defaultLabel = 'phone number';
export type PhoneFormItemProps = {
  /** 🔥 Whether rules are required to add the required verification (no labelRequired=true is required when true) */
  phoneRequired?: boolean;
  /** 🔥 Whether rules are added to regular check (/^1[2-9]\d{9}$/), default true */
  phoneFormatCheck?: boolean;
  /** Input other properties */
  inputProps?: InputProps;
} & FormItemProps;
/** Mobile phone number form (with ) */
export const PhoneFormItem = (props: PhoneFormItemProps) => {
  const {
    phoneRequired = false,
    phoneFormatCheck = true,
    inputProps,
    ...formItemProps
  } = props;
  const resultRules = useMemo(() => {
    const arr = [...( || [])];
    if (phoneFormatCheck) {
      ({
        validator(val: string | undefined, cb: (error?: ReactNode) => void) {
          const realVal = (`${val}` as any).replaceAll(' ', '');
          if (!val || /^1[2-9]\d{9}$/.test(realVal)) {
            cb();
          } else {
            cb(`Please enter the correct one${formItemProps?.label || defaultLabel}`);
          }
        },
      });
    }
    if (phoneRequired) {
      ({
        validator(val: string | undefined, cb: (error?: ReactNode) => void) {
          if (!val) {
            cb(`Please enter${ || defaultLabel}`);
          } else {
            cb();
          }
        },
      });
    }
    return arr;
  }, [
    ,
    ,
    phoneFormatCheck,
    phoneRequired,
  ]);
  const normalize = usePersistCallback((val: string | undefined) => {
    if (val) {
      const realVal = (`${val}` as any).replaceAll(' ', '');
      if (val !== realVal) {
        return realVal;
      }
    }
    return val;
  });
  const resultInputProps = {
    allowClear: true,
    ...inputProps,
    placeholder:
      inputProps?.placeholder || `Please enter${ || defaultLabel}`,
  };
  return (
    <
      normalize={normalize}
      rules={resultRules}
      {...formItemProps}
      required={ || phoneRequired}
    >
      <Input {...resultInputProps} />
    </>
  );
};

I used to use vue, and reacted every day after I got bytes. I felt like I had changed a lot, or maybe I was already outrageous.

The above is the detailed content of the Byte Encapsulated React component's mobile phone number automatic verification format FormItem. For more information about the React Encapsulated Mobile Phone Number Verification Format, please pay attention to my other related articles!