React: React thinks that my input is readonly but it is not

Created on 12 Sep 2016  路  8Comments  路  Source: facebook/react

I want to report a bug.

I have an input the value of which is set from this.state. And this value is manipulated using onKeyDown event. In my console i have the next error:

Warning: Failed form propType: 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. Check the render method of TimePicker.
So my input is not readonly it gets edited which means that this error is nonexistent.

To reproduce this you could add an <input /> with value from this.state and onKeyDown handler and no onChange handler. Something like this:

class MyInput extends React.Component {
  _onKeyDown(e) {
    this.setState({
      inputValue: this.state.inputValue + "."
    });
  }

  render() {
    return (
      <input type="text" onKeyDown={this_onKeyDown.bind(this)} value={this.state.inputValue} />
    );
  }
}

The expected behavior would be the same but without console error. My component works exactly as i expect.

React v15.3.1

Most helpful comment

@non-binary

Maybe unrelated (a heckin' React beginner) but I came across this post when searching so might as well add for the next traveller. When passing a value to the input field using this.props use defaultValue instead of value since value makes it read-only for some reason.

Got linked to this as well: https://reactjs.org/docs/uncontrolled-components.html (thanks @philipp-spiess)

From one heckin' React beginner to another, THANK YOU!!!!!!

All 8 comments

Replace onKeyDown with onChange, onKeyDown is not what you want in this case.

@syranide In my component it is exactly what I want. I edit the state depending on the key pressed. I allow only some keys to change the value. Also I replace removed characters if delete or backspace is pressed. I use event.target.selectionStart and event.target.selectionEnd for removing more than one character. I'm alsmost 100% sure that it would not be possible with onChange because the event.target.value is the changed one so i would not be able to access old selection range.

Of course, I could choose the wrong route to how to implement this, but working with onKeyDown looked like the right option for me.

@dyarmosh There are lots of ways to change the value of an input without pressing keys. Also, if you're going to modify the behavior of the input as extensively as you've done I would personally recommend not using the built-in controlled behavior and just implement it yourself instead.

@syranide I'm sorry, I didn't quite get what you meant by "implement it yourself". Do you suggest me to implement this in plain javascript instead of react component or not using input at all?

@dyarmosh Simply to not use the controlled logic of React inputs (i.e. value), use defaultValue and update the value of the input yourself using JS. That way you control the exact behavior/timing yourself.

I'm going to close this, because as @syranide mentioned using onKeyDown does not fully control the value of the input as it breaks with input like pasted text. The warning does offer a working alternative as well (using defaultValue and managing the input value), so it seems fine to me.

If you don't care about pasted text, or other types of input, and you don't want to use defaultValue, you can always pass in an empty onChange function to stop the warning, though YMMV with that.

@dyarmosh feel free to continue asking any clarifying questions here though! 馃憤

Maybe unrelated (a heckin' React beginner) but I came across this post when searching so might as well add for the next traveller. When passing a value to the input field using this.props use defaultValue instead of value since value makes it read-only for some reason.

Got linked to this as well: https://reactjs.org/docs/uncontrolled-components.html (thanks @philipp-spiess)

@non-binary

Maybe unrelated (a heckin' React beginner) but I came across this post when searching so might as well add for the next traveller. When passing a value to the input field using this.props use defaultValue instead of value since value makes it read-only for some reason.

Got linked to this as well: https://reactjs.org/docs/uncontrolled-components.html (thanks @philipp-spiess)

From one heckin' React beginner to another, THANK YOU!!!!!!

Was this page helpful?
0 / 5 - 0 ratings