How to "onchange" in ReactJS

21 October 2015   22 comments   Javascript, ReactJS

Normally, in vanilla Javascript, the onchange event is triggered after you have typed something into a field and then "exited out of it", e.g. click outside the field so the cursor isn't blinking in it any more. This for example

document.querySelector('input').onchange = function(event) {
  document.querySelector('code').textContent = event.target.value;
}

First of all, let's talk about what this is useful for. One great example is a sign-up form where you have to pick a username or type in an email address or something. Before the user gets around to pressing the final submit button you might want to alert them early that their chosen username is available or already taken. Or you might want to alert early that the typed in email address is not a valid one. If you execute that kind of validation on every key stroke, it's unlikely to be a pleasant UI.

Problem is, you can't do that in ReactJS. It doesn't work like that. The explanation is quite non-trivial:

*"<input type="text" value="Untitled"> renders an input initialized with the value, Untitled. When the user updates the input, the node's value property will change. However, node.getAttribute('value') will still return the value used at initialization time, Untitled.

Unlike HTML, React components must represent the state of the view at any point in time and not only at initialization time."*

Basically, you can't easily rely on the input field because the state needs to come from the React app's state, not from the browser's idea of what the value should be.

You might try this

var Input = React.createClass({
  getInitialState: function() {
    return {typed: ''};
  },
  onChange: function(event) {
    this.setState({typed: event.target.value});
  },
  render: function() {
    return <div>
        <input type="text" onChange={this.onChange.bind(this)}/>
        You typed: <code>{this.state.typed}</code>
      </div>
  }
});
React.render(<Input/>, document.querySelector('div'));

But what you notice is the the onChange handler is fired on every key stroke. Not just when the whole input field has changed.

So, what to do?

The trick is surprisingly simple. Use onBlur instead!

Same snippet but using onBlur instead

var Input = React.createClass({
  getInitialState: function() {
    return {typed: ''};
  },
  onBlur: function(event) {
    this.setState({typed: event.target.value});
  },
  render: function() {
    return <div>
        <input type="text" onBlur={this.onBlur.bind(this)}/>
        You typed: <code>{this.state.typed}</code>
      </div>
  }
});
React.render(<Input/>, document.querySelector('div'));

Now, your handler is triggered after the user has finished with the field.

Comments

Jack
Thanks for this.
Anonymous
hi jack
Anonymous
didnt work for me
JJ
Nice, worked for me. Could you perhaps elaborate on why onBlur works, and what is the actual use case for onBlur? Thank you!
AJ Farkas
Good write-up. You can clean up the code even more by removing `.bind(this)`: `this` always refers to the React component here.
RnMss
I don't think so. If you don't bind `this`, `this` would be the `event.target` ( the instance of <input> ).
Your case is probably because you always use the ES6 arrow function ( (args)=>{...} ), which treats `this` as a normal variable. This is unlike a classic anonymous "function (args) { ... }".
Sergei Gribovskii
No, that's because React now binding it by itself. So You don't need to use it. And to say more you have to not use it. Not if you need to pass some params for example you need to type .bind(null, param1, param2). Just read the updated documentation of React.
Anonymous
Unless you are Using ES6 syntax where .bind(this) is needed. Using ES5 and older syntax, You do not need to .bind(this).

Reference: https://toddmotto.com/react-create-class-versus-component/
vlakov
Thank you, very useful.
There are more wrong ways than there are good ways of using "this". It is ridiculous how simple things can be done the wrong way. Smart people devising new ways for stupids like me to shoot in the leg :-)).
---
https://daveceddia.com/avoid-bind-when-passing-props/
---
Anonymous
Thanks, It work for me
Anonymous
Thanks a lot , it worked for me
liuzhigang
works for me.
Jeveen Shrestha
Thanks, it works for me.
Mike Rehy
saved my form! thanks
Roman Stejskal
Note that the native implementation (at least in Chrome) of `onChange` and `onBlur` is not the same!

`blur` only triggers once you click (or tab) out of the input (when the input loses focus), whereas `change` can also be triggered by hitting the Enter key!
Yacoub Oweis
You are absolutely right about the "Enter key", and this is very important in many cases to maintain a good user experience for the form elements. A simple solution to adopt the behavior of the Enter key is this code snip-it:

<input type="text" onBlur={this.onBlur} onKeyPress={this.handleEnterKeyPress} />

handleEnterKeyPress: function (e) {
        if(e.which == 13){
            e.target.blur();
        }
        return false;
}
Andreas Susilo
Thanks. It works!
Spiryt Sista
Thanks!
Anoop John
Thanks... this helped immensely!!
Anonymous
THanks!!
Gerald
Thanks, was a huge help!
ketan
Using **defaultValue** attribute worked for me in case of onblur.

Your email will never ever be published


Related posts

Previous:
And bash basics 16 October 2015
Next:
Weight of your PostgreSQL tables "lumped together" 31 October 2015
Related by Keyword:
10 Reasons I Love create-react-app 04 January 2017
How to deploy a create-react-app 04 November 2016
Visual speed comparison of AngularJS and ReactJS 20 July 2015
Careful when dealing with options in IE 14 April 2006
Related by Text:
jQuery and Highslide JS 08 January 2008
I'm back! Peterbe.com has been renewed 05 June 2005
Anti-McCain propaganda videos 12 August 2008
I'm Prolog 01 May 2007
Ever wondered how much $87 Billion is? 04 November 2003