var React = require('react'),
Backbone = require('backbone'),
Flux = require('flux'),
dispatcher = new Flux.Dispatcher();
var storeListeningMixin = {
componentDidMount: function () {
if (this.props.store && this.onStoreChanged) {
this.props.store.on('change:emit', this.onStoreChanged, this);
}
},
componentWillUnmount: function () {
if (this.props.store && this.onStoreChanged) {
this.props.store.off('change:emit', this.onStoreChanged);
}
}
};
var dispatchingMixin = {
componentWillMount: function () {
this.dispatch = function (payload) {
dispatcher.dispatch(payload);
};
}
};
function register(store) {
store.dispatcher = dispatcher;
store.dispatchId = dispatcher.register(store.onDispatch.bind(store));
}
function unregister(store) {
delete store.dispatcher;
dispatcher.unregister(store.dispatchId);
}
var Store = Backbone.Model.extend({
checked: [false, false],
onDispatch: function (payload) {
if (payload.actionType === 'ha') {
console.log('dispatch received for checkbox' + payload.ind + '.');
this.checked[payload.ind] = !this.checked[payload.ind];
this.trigger('change:emit');
}
}
});
var store = new Store();
var Checkboxa = React.createClass({
mixins: [dispatchingMixin],
onChange: function(e) {
console.log('dispatching...');
e.preventDefault(); // This makes the checkbox behave weirdly - if removed things are normal
this.dispatch({actionType: 'ha', ind: this.props.ind});
},
render: function() {
var checked = this.props.store.checked[this.props.ind];
console.log('checkbox rendering, should be checked: ' + checked);
return (
<li><input type="checkbox" checked={checked} key={this.props.ind}
onChange={this.onChange}/><span>{this.props.ind}</span></li>
);
}
});
var CheckboxaList = React.createClass({
mixins: [storeListeningMixin],
onStoreChanged: function() {
this.forceUpdate();
},
render: function() {
return (
<ul>
<Checkboxa ind={0} key={0} store={this.props.store} />
<Checkboxa ind={1} key={1} store={this.props.store} />
</ul>
);
}
});
register(store);
React.render(
<CheckboxaList store={store}/>,
document.getElementById('renderArea')
);
Notice how clicking the checkbox does not make React render it according to the checked state, but clicking the other checkbox causes the checkbox to re-render correctly.
In theory the preventDefault() happened when the component was dispatching and shouldn't affect the rendering? In any case the component shouldn't be rendered incorrectly?
this is because under the hood react listens for Click events instead of Change to normalize browser differences. The accepted solution is: don't use preventDefault (use stopPropagation instead) or make use of a timeout. more reading here https://github.com/facebook/react/issues/3005
@jquense Can you maybe detail exactly what is going on? The effect is still observed when you use onClick directly. Can you maybe give me a flow of how this is happening?
@tigergrid you can read the issue I linked, zpao covers it quite nicely. https://github.com/facebook/react/issues/3005#issuecomment-72513965
essentially you are running into a limitation of how react implements the onChange event for checkboxes
This is unfortunate but the way it is for now. If you don't have a good reason for using preventDefault(), don't.
Most helpful comment
this is because under the hood react listens for Click events instead of Change to normalize browser differences. The accepted solution is: don't use preventDefault (use stopPropagation instead) or make use of a timeout. more reading here https://github.com/facebook/react/issues/3005