3

Since change events are fired for input in some browsers only (namely IE) only when the focus is lost, my understanding is that the click event is a better way to listen for changes (see Getting value of HTML Checkbox from onclick/onchange events ).

However, when I only supply only the checked property with an onClick handler to a controlled input element in react, it complains with:

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

What is the solution here? The react documentation seems to suggest using onChange, but that conflicts with the recommendations in the answer listed above.

Adam Thompson
  • 3,278
  • 3
  • 22
  • 37
  • @RahulSharma unfortunately, no - it is a controlled component in my case. – Adam Thompson May 27 '20 at 18:33
  • 2
    React [wraps the browser's native events](https://reactjs.org/docs/events.html) to provide a normalized interface. I can find [one Github comment](https://github.com/facebook/react/issues/1471#issuecomment-123441828) from 2015 which says the following: *"... react uses the native click event to listen to user interaction with the radio, and then calls the onchange for the input. The reason for this (at least according to the comment in the code) is because IE8 does not fire the change event until blur ..."* - so it sounds like this may already be handled. Have you tried? – cbr May 27 '20 at 18:40
  • What issue are you experiencing specifically with using change such as the react based answer in the question you posted in your question? https://stackoverflow.com/a/56632316/5059657 – Alexander Staroselsky May 27 '20 at 18:41
  • 1
    Looking at [React's code](https://github.com/facebook/react/blob/9751935abfa5585623f3ee85bb3c4eff4154e376/packages/react-dom/src/events/plugins/ModernChangeEventPlugin.js#L219-L229), it looks like to me that the edge case with IE which you mentioned is already handled, and that `onChange` would behave like you would expect on a modern browser. I would just use `onChange` instead of worrying about it yourself unless you can test it yourself. – cbr May 27 '20 at 18:48
  • @cbr nice! Yeah that makes sense and I kind of suspected something like that was going on but couldn't find anything on it - thank you (you should leave an answer!) – Adam Thompson May 27 '20 at 18:49
  • 1
    Sure, give me a second! – cbr May 27 '20 at 18:50

1 Answers1

3

React provides a cross-browser wrapper called SyntheticEvent to provide a normalized interface to events, but the documentation doesn't explicitly state which cases are or are not handled. Regarding the edge case with IE, this Github comment from 2015 suggests that it's already handled:

... react uses the native click event to listen to user interaction with the radio, and then calls the onchange for the input. The reason for this (at least according to the comment in the code) is because IE8 does not fire the change event until blur, so in order to be 'compatible' with IE8, the click event is used.

Looking at React's source, to me it strongly looks like this indeed is the case:

function shouldUseClickEvent(elem) {
  // Use the `click` event to detect changes to checkbox and radio inputs.
  // This approach works across all browsers, whereas `change` does not fire
  // until `blur` in IE8.
  const nodeName = elem.nodeName;
  return (
    nodeName &&
    nodeName.toLowerCase() === 'input' &&
    (elem.type === 'checkbox' || elem.type === 'radio')
  );
}

So I would just use onChange like you would on a modern browser, and worry about doing it yourself (or even opening a new issue in React's repo) if you find the behavior to differ on IE.

cbr
  • 12,563
  • 3
  • 38
  • 63