lucasbasquerotto / react-masked-input

MIT License
28 stars 0 forks source link

Usage with React-Hook-Form #5

Closed lyvyu closed 5 months ago

lyvyu commented 5 months ago

Hi,

First of all I want to thank you for giving the option to have some text masked without the need of the input itselt, only the text. Amazing job.

Now, I'm trying to make it work with the react-hook-form and it does not really work much. The thing is, the value is masked, all good, but when the onChange is triggered, it would update the value but it's like, the old value is pushed back and it's reformatting the old value. In the end, I cannot enter anything in a controlled input as it would not change.

See my implementation below:

// The masked imput
const PhoneMaskedInput = forwardRef(
  (
    { value: outerValue, onChange: onChangeOuter }: Props,
    outerRef: React.ForwardedRef<HTMLInputElement> | undefined
  ) => {
    const { value, onChange, ref } = useWebMask({
      maskGenerator: createDefaultMaskGenerator('(999) 999-9999'),
      value: outerValue,
      onChange: onChangeOuter,
      keepMask: false,
      ref: outerRef,
    });

    return (
      <Input value={value} onChange={onChange} ref={ref as Ref<InputRef>} />
    );
  }
);

export default PhoneMaskedInput;

// The actual controlled component that implements the masked input
const PhoneNumberInput = <TFieldValues extends FieldValues = FieldValues>({
  control,
  name,
  label,
}: PhoneNumberInputProps<TFieldValues>) => {
  return (
    <Controller
      control={control}
      name={name}
      render={({ field: { value, onChange, ref } }) => (
        <Form.Item label={label}>
          <PhoneMaskedInput onChange={onChange} value={value} ref={ref} />
        </Form.Item>
      )}
    />
  );
};

export default PosPhoneNumberInput;

Maybe I'm missing something or I did something wrong but can't seem to sort that one out.

Hope hearing from you soon, cheers!

lucasbasquerotto commented 5 months ago

@lyvyu I tested your case and it worked for me:

const PhoneMaskedInput = React.forwardRef(
    (
        { value: outerValue, onChange: onChangeOuter }: any,
        outerRef: React.ForwardedRef<HTMLInputElement> | undefined,
    ) => {
        const { value, onChange, ref } = useWebMask({
            maskGenerator: createDefaultMaskGenerator('(999) 999-9999'),
            value: outerValue,
            onChange: onChangeOuter,
            keepMask: false,
            ref: outerRef,
        });

        return <input value={value} onChange={onChange} ref={ref} />;
    },
);

// The actual controlled component that implements the masked input
const PhoneNumberInput = ({ control, name, label }: any) => {
    return (
        <Controller
            control={control}
            name={name}
            render={({ field: { value, onChange, ref } }) => (
                <PhoneMaskedInput onChange={onChange} value={value} ref={ref} />
            )}
        />
    );
};

const TestForm = () => {
    const { control, register, handleSubmit } = useForm();

    return (
        <form onSubmit={handleSubmit((data) => console.log('data', data))}>
            <PhoneNumberInput {...register('testField')} control={control} />
            <input type="submit" />
        </form>
    );
};

I used any in some places because I don't know the types your are using. I also removed the Form component because I don't know from where it comes from.

I tested using both the HTML input (as shown above) as well as the @mui/material Input, and both worked.

My guess is that you are using an input that is not equivalent to the HTML input (it should behave as an HTML input to work, because the useWebMask onChange expect to receive an input event with event.target.value).

If your Input is not equivalent to the HTML input, you can use useRefMask and define the state change there similar to how it was implemented in the useWebMask hook https://github.com/lucasbasquerotto/react-masked-input/blob/master/src/hooks/use-web-mask.ts).

My suggestion is to initially use the code I posted above and see if it works for you. Then, go doing changes step by step toward the code you posted to see which step causes the error.

lyvyu commented 5 months ago

Hey @lucasbasquerotto, thanks for the reply man, I really appreciate it.

Actually you might be just right, it seems to be working fine. I just created a sandbox and in the sandbox it's working, which I can't say about my project. https://codesandbox.io/p/sandbox/react-hook-form-rq6y2r

I'm using Ant Design actually for the components and the Input is expecting as a DOM HTML input.

Anyways, I guess there's no issue on the lib side but instead something wrong is with my codebase for some reason. Don't know even why's that happening.

I shall thank you for this amazing library and the detailed response 🙌

lucasbasquerotto commented 5 months ago

Thanks, @lyvyu! Great to know!

I will close this issue then, but feel free to open it if needed.