React: onChange not firing on controlled input element when `value` is updated

Created on 9 Feb 2017  路  6Comments  路  Source: facebook/react

I've found what to me appears as a bug.

Bug

When a controlled input element changes by updating it's value, onChange isn't called.

Reproduction

I made a codepen that illustrates the problem; http://codepen.io/pudgereyem/live/bgmvOq

Expected behaviour

I expect that onChange gets called, since the <input/> did change, and the world of React is by nature very much "controlled".

This is written in the docs and also mentioned in various threads such as https://github.com/facebook/react/pull/8550#issuecomment-266248335 and https://github.com/facebook/react/issues/8696#issuecomment-270909834.

My problem

The fact that the inputs onChange function not gets called is a problem to me, because I need to do logic (such as validation) when the inputs have changed.

Comments

  • I tried using onInput also, but it doesn't get called either

Most helpful comment

Thanks for the report @pudgereyem, the example was really useful! This is expected behavior. The onChange event handler is meant to act like a typical event handler does, meaning its only invoked when the DOM dispatches the appropriate event. Although we treat onChange as a special case by changing its behavior to better match user expectations, it's still meant to be a standard event handler.

Check out this example that uses plain JavaScript:

var input = document.getElementById('input')

// This is only called when the input value
// is changed via the DOM, not when its changed
// programmatically using input.value
input.onchange = (e) => {
  window.alert(e.target.value)
}

setTimeout(() => {
  input.value = "changed"
}, 1000)

No change event is fired when input.value is updated, as there was technically no change event. This mirrors what React is doing. I see how it might be useful for React to invoke onChange whenever it detects that value has changed, but as of now that's not the expected behavior.

The fact that the inputs onChange function not gets called is a problem to me, because I need to do logic (such as validation) when the inputs have changed.

If the value is coming from props then you can always check the new value in componentWillReceiveProps

All 6 comments

It actually works for me, every time I change the input field I see the 'CHANGE' text inside console.
The problem why your input is always empty is that you didn't dispatch any action to change firstName inside props, except the click button.

you can check my pen http://codepen.io/eduardb/pen/zNmmRN with fix

Hi @eduardbcom, yeah of that I know. I guess my example wasn't 100% clear. What you should try doing is to click the button and watch for the 'CHANGE' inside the console. You don't get one when you are updating the value if you _are not_ touching the input.

I'll update my codepen so this is more clear by adding the functionality you thought was missing.

EDIT: I've now updated the Codepen to make it more clear that the problem is when when you are trying to update the <input/> by "just passing" a new value to it.

Thanks for the report @pudgereyem, the example was really useful! This is expected behavior. The onChange event handler is meant to act like a typical event handler does, meaning its only invoked when the DOM dispatches the appropriate event. Although we treat onChange as a special case by changing its behavior to better match user expectations, it's still meant to be a standard event handler.

Check out this example that uses plain JavaScript:

var input = document.getElementById('input')

// This is only called when the input value
// is changed via the DOM, not when its changed
// programmatically using input.value
input.onchange = (e) => {
  window.alert(e.target.value)
}

setTimeout(() => {
  input.value = "changed"
}, 1000)

No change event is fired when input.value is updated, as there was technically no change event. This mirrors what React is doing. I see how it might be useful for React to invoke onChange whenever it detects that value has changed, but as of now that's not the expected behavior.

The fact that the inputs onChange function not gets called is a problem to me, because I need to do logic (such as validation) when the inputs have changed.

If the value is coming from props then you can always check the new value in componentWillReceiveProps

I can just add that you can use refs to emit change event by hand.

@aweary Thanks alot for the fast response.

I see how it might be useful for React to invoke onChange whenever it detects that value has changed, but as of now that's not the expected behavior.

Got it! Yes, it's an interesting discussion I think. I understand that it's now only meant to be a standard event handler. However, the input did change, so it would be neat if onChange would trigger also.

@eduardbcom yes I know, but thanks for adding that!

Hi @aweary and @eduardbcom,

Here is a new pen with a solution to my problem where I manually trigger onChange handler when input's value is updated: http://codepen.io/pudgereyem/live/OWBrdv

Achieved using componentWillReceiveProps as suggested by @aweary. Closing the issue.

Was this page helpful?
0 / 5 - 0 ratings