GoncharukOrg / react-input

109 stars 9 forks source link

Reset the mask after it changes #11

Closed a1r93 closed 1 year ago

a1r93 commented 1 year ago

Hello, I'm having an issue with the useMask hook. I have a dropdown that allows me to select a format for a bank account, see an example of possible options below:

[{
    "country": "Albania",
    "length": "28",
    "code": "AL",
    "format": "__ ____ ____ ____ ____ ____ ____"
  },
  {
    "country": "Belgium",
    "length": "16",
    "code": "BE",
    "format": "__ ____ ____ ____"
  }]

By default I have Albania selected, the mask displayed has the expected format. Once I change it to be Belgium I would expect the format to be updated, but it doesn't get replaced until I type a number.

Is there any clean way to achieve this? Currently I call the useMask hook like so:

const currentMask = ibanFormats.find(
    (format) => format.code === selectedCountry
  )?.format;

  const inputRef = useMask({
    mask: currentMask,
    replacement: { _: /\d/ },
    showMask: true,
  });

And pass the inputRef to the input like this: <input ref={inputRef} />

Thanks for your help :)

GoncharukBro commented 1 year ago

Good afternoon,

The essence of the @react-input/mask tool is that it focuses only on user input, thus preserving the standard behavior of the input element. However, you can force the InputMask component (provided by the library) to be recreated by changing the key value as shown in the example below:

import { useState } from "react";

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

const countries = [
  {
    country: "Albania",
    format: "__ ____ ____ ____ ____ ____ ____"
  },
  {
    country: "Belgium",
    format: "__ ____ ____ ____"
  }
];

export default function App() {
  const [mask, setMask] = useState(countries[0].format);

  return (
    <div>
      {countries.map(({ country, format }) => (
        <button key={country} type="button" onClick={() => setMask(format)}>
          {country}
        </button>
      ))}

      <InputMask key={mask} mask={mask} replacement={{ _: /\d/ }} showMask />
    </div>
  );
}

You can also change the value of the input element:

import { useState } from "react";

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

const countries = [
  {
    country: "Albania",
    format: "__ ____ ____ ____ ____ ____ ____"
  },
  {
    country: "Belgium",
    format: "__ ____ ____ ____"
  }
];

export default function App() {
  const [mask, setMask] = useState(countries[0].format);
  const [value, setValue] = useState(countries[0].format);

  const inputRef = useMask({
    mask: mask,
    replacement: { _: /\d/ },
    showMask: true
  });

  const handleChangeFormat = (format) => {
    setMask(format);
    setValue(format);
  };

  return (
    <div>
      {countries.map(({ country, format }) => (
        <button
          key={country}
          type="button"
          onClick={() => handleChangeFormat(format)}
        >
          {country}
        </button>
      ))}

      <input
        ref={inputRef}
        value={value}
        onChange={(event) => setValue(event.target.value)}
      />
    </div>
  );
}
a1r93 commented 1 year ago

Thanks this seems to be working fine! :)