Reputation: 5136
I have a simple React component:
state = {
value: '',
};
render() {
return <select onChange={this.handleChange} value={this.state.value}>
<option value="">--</option>
<option value="1">One</option>
</select>;
}
handleChange = (e) => {
this.setState({
value: e.target.value,
});
console.log('Handling Change!!')
};
I want to be able to trigger the event handler programmatically via ordinary javascript or, in this example, jQuery.
$select = $('select');
$select.val('1');
// then
$select.trigger('change');
// or
$select.trigger('input');
But none of these trigger the onChange
handler in the React component, and therefore the state doesn't get updated.
My question: How can I trigger the onChange
handler using the DOM and Javascript?
[edit]
To clarify a bit further, I am mounting the React Component like this:
el = document.createElement('div')
ReactDOM.render(MySelect, el)
$select = $(el).find('select');
$select.val('1');
// then
$select.trigger('change');
// or
$select.trigger('input');
Upvotes: 4
Views: 5352
Reputation: 5136
Answering my own question, for posterity.
The issue, it turned out, was twofold. But first, some background:
React Events
The React event system listens for native DOM events by delegating to the root node. I.e. it doesn't attach listeners to each element with onChange
, but just listens on the root document for events that bubble up through the DOM.
For those familiar with jQuery delegated events, this would be analogous to something like
$(document).on('change', '.my-select', callback)
jQuery Events
Secondly, jQuery itself somewhat 'overrides' the DOMs native event bubbling with its own system, which is how you can throw around custom events.
#The solution...#
As mentioned, I had 2 problems, and hence 2 solutions:
##First##
Because of jQuery using its own event system, events fired with
$(select).trigger('change')
will not reach React's root event listener. So we go native with...
select.dispatchEvent(new Event('change', {bubbles: true}));
...but that's still not enough.
##Second##
DOM events bubble up from the element to the document root. BUT notice that I never attached my element to the document!! The change
event bubbles up to... nowhere! Again, it never reaches the React event listener registered on the document.
If I add my element to the DOM like this:
el = document.createElement('div')
ReactDOM.render(MySelect, el)
document.body.appendChild(el) // <-- attach to DOM
Now the event reaches the React event listener, and the original onChange
handler in my component is fired.
I hope this helps anyone who comes across something similar.
ps. I found the documentation in this reactjs file helpful in understanding the React event system: https://github.com/facebook/react/blob/master/packages/react-dom/src/events/ReactBrowserEventEmitter.js
Upvotes: 11