javascriptreactjsinputonchangemaskedinput

Problem with onChange for Masked Input in React


I am trying to create a masked input in React (without using a masked input library). My problem is that I could not access e.key using the onchange prop -- it just gives me undefined, so I used onKeyDown instead -- this is working, but I am getting a warning in the console that says :

"Warning: Failed prop type: You provided a value prop to a form field without an onChange handler. This will render a read-only field. If the field should be mutable use defaultValue. Otherwise, set either onChange or readOnly."

I have tried using keyDown to get the key, and then masking the input using the onChange function, but it is always one character behind where it should be.

This is what my code looks like so far, I would be so appreciative of any tips, etc. that could fix this.

class App extends Component {
  state={
    input: "",
    acc: "", //this is an accumulator I'm using to hold the unmasked version of the input
    currentKey: ""
  }

  getKey = (e) => {
    if(e.key === "Backspace"){ //removes last letter on backspace
      const lastLetterRemoved = this.state.acc.substr(0,this.state.acc.length-1)
      this.setState({acc: lastLetterRemoved, input: this.mask(lastLetterRemoved)})
    } else {
      let currentChar;
      if(!Number(e.key)){//ignores non-numeric characters
          currentChar = ""
      } else {
        currentChar=e.key //adds current key to accumulator, masks it and sets input value
        const currentAcc = this.state.acc + currentChar
        this.setState({acc: currentAcc, input: this.mask(currentAcc)})
      }
    }
  }

//function to mask the input as the user types the Numbers should appear
//already formatted as an amount of currency
//example: inputting 123 would behave like this $0.01 ... $0.12 ... $1.23
  mask = (num) => {
    let dollars;
    let cents;
    if(num<10){
      dollars = "0"
      cents = `0${num}`
    } else {
      dollars=Math.floor(num/100)
      cents=num%100
    }
    return `$${dollars}.${cents}`
  }


  render() {
    return (
      <div className="App">
        <header className="App-header">
          <input 
          value={this.state.input || "$0.00"} //value is $0.00 to start, then it is whatever the input is
          onKeyDown={this.getKey}/>
        </header>
      </div>
    );
  }
}

export default App;

Thank you in advance for any pointers!


Solution

  • There is a long conversation going on at a related issue on React Github Repo. And there is no elegant solution provided yet.

    The simplest solution at the moment to remove this warning is, addind a seperate dummy onChange prop (onChange={() => {}}) to the input element as suggested in this post