GoncharukOrg / react-input

109 stars 9 forks source link

onMask handler makes input uncontrolled #27

Open hadeji33 opened 5 months ago

hadeji33 commented 5 months ago

When adding the onMask handler, the value of the input field changes even if we strictly specified the value prop of the element. This can be demonstrated by modifying the original example as follows:

import { useMask } from "@react-input/mask";

export default function Input() {
  const inputRef = useMask({
    mask: "+1 (___) ___-__-__",
    replacement: { _: /\d/ },
    onMask: console.log,
  });

  return (
    <input ref={inputRef} value={"+1 (555"} placeholder="+1 (___) ___-__-__" />
  );
}

We can see this when we want to implement a controlled input component that receives value and onChange props from outside:

import { useMask, type MaskEvent } from "@react-input/mask";

import { useState } from "react";

export type InputProps = {
  value?: string;
  defaultValue?: string;
  onChange?: (neValue: string) => void;
};

export default function Input({ value, defaultValue, onChange }: InputProps) {
  const [innerValue, setInnerValue] = useState(defaultValue);

  const handleMask = (event: MaskEvent) => {
    setInnerValue(event.detail.value);
    onChange?.(event.detail.value);
  };

  const inputRef = useMask({
    mask: "+1 (___) ___-__-__",
    replacement: { _: /\d/ },
    onMask: handleMask,
  });

  return (
    <input
      ref={inputRef}
      value={value ?? innerValue}
      placeholder="+1 (___) ___-__-__"
    />
  );
}
GoncharukBro commented 2 months ago

In your example, you get input control both if you pass an external value and vice versa. Perhaps your example is incomplete?

Starting with @react-input/mask@2.0.0, we removed the input-mask event and the onMask method, focusing only on using native React events and methods such as onChange, since the input-mask event cannot be explicitly coordinated with React events and methods, making such usage and event firing order non-obvious.

To use the useful data from the detail property of the input-mask (onMask) event object, you can also use the utilities described in the «Utils» section.

The release of @react-input/mask@2.0.0 is expected next week.

Tip: Don't change internal and external state at the same time, this applies not only to this library but to all components that have internal state.