4

I'm trying to emulate standard DOM onchange event behavior in React. The React onChange event acts like the DOM oninput event, firing every time a key entry is made, rather than when the entry is complete. This makes verifying input difficult unless you use a separate submit button (which I don't). I believe this to be a bug in React.

So far, I've discovered the following techniques come close:

  • Emulate submit on loss of focus via an onBlur event handler that submits the value when the focus is lost.
  • Emulate submit on hitting the return/enter key via an onKeyUp event handler that submits the entry when evt.key is "Enter" or "Accept".
  • For numeric input, emulating submit on increment/decrement (Safari input up/down arrows, up/down keys, up/down scroll wheel) by having the onChange handler detect when the change in value is equal to the step and being careful to compare within a reasonable epsilon for non-integer steps. Number.EPSILON was too small for steps of 0.1, so I had to use something bigger (but still very small). This only approximates the DOM behavior: If a user selects the last digit and provides a digit that changes the value by the step, it will also submit when the digit is entered.

Am I missing any cases? Is there a better technique?

srkleiman
  • 607
  • 8
  • 16
  • 2
    "I believe this to be a bug in React"... No matter the question that follows, this is very very unlikely. If you do find a bug with React or another library, SO is not the place for it, instead open an issue in the library's repo. – Brian Thompson Jun 01 '21 at 21:02
  • have you tried to put a reference on the input and add an even listener inside a useEffect? – Luis Sardon Jun 01 '21 at 21:04
  • onBlur seems to be the conclusion [here](https://stackoverflow.com/questions/38256332/in-react-whats-the-difference-between-onchange-and-oninput) – Nikki9696 Jun 01 '21 at 21:07
  • I believe using a `
    ` should be triggered if you hit return/enter on any input inside the form.
    – Rômulo Bourget Novas Jun 01 '21 at 21:08
  • 2
    It's not a bug. https://reactjs.org/docs/dom-elements.html#onchange – Aaron Kvarnlov-Leverty Jun 01 '21 at 21:09
  • I meant bug because they call onChange a "misnomer". The DOM onchange behavior is both useful and distinct from oninput. React makes it difficult to duplicate this functionality (i.e. submit on blur, return, or increment/decrement) for no good reason that I can think of. I don't think onSubmit duplicates all this behavior. – srkleiman Jun 02 '21 at 00:59

2 Answers2

2

This is not a recommended approach, BUT, if you have to do something such a custom hook, it could be like this (pretty basic though):

Notice I'm using defaultValue instead of value because native 'change' event doesn't trigger as you type.

function useOnChange(handleOnChange) {
  const ref = React.createRef(null);
  
  React.useEffect(() => {
     ref.current.addEventListener('change', handleOnChange);
  }, []);
  
  return ref;
}

function App() {
  const [value, setValue] = React.useState(0);
  const onChangeRef = useOnChange((e) => {
    console.log('on change', e.target.value)
    setValue(e.target.value);
  });
  
  return (
    <div className="App">
      <input type="number" defaultValue={value} ref={onChangeRef} />
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Luis Sardon
  • 516
  • 3
  • 8
  • This works great! Thanks! I used a separate React onChange handler to update the value in addition to the addEventListener handler. This avoids using defaultValue. – srkleiman Jun 02 '21 at 01:29
1

You should use Debounce method for such a functionality. You can pass the event handler function within the debounce method and a delay (in milliseconds).

So when you are typing a text and you want to call the event handler after the user has typed. Using the debounce function, the event handler will be called after a delay after the user stopped typing.

Edit:

You can read more about it from here - link

Winter
  • 341
  • 1
  • 4
  • 8