Change:
Appears to be working in Firefox but at least Chrome & Safari are broken. Should be a really recent regression so very few possible changes to blame... Easiest repo: the todo list on our homepage.
Just a heads up but this still seems to be an issue even on 15.4.1. I've been struggling to reproduce this because it seems to be some sort of ninja bug. Nevertheless, I was wondering if anyone is still dealing with this problem?
I haven't seen anything.
I'm still seeing this issue.
Please open a new issue with a simplified repro case if you're still seeing this!

Discussion:
'use strict'; var ReactChildren = require('ReactChildren'); <ins> var ReactDOMComponentTree = require('ReactDOMComponentTree'); </ins> var ReactDOMSelect = require('ReactDOMSelect'); var warning = require('warning');

inst._wrapperState = {selected: selected}; }, <ins> postMountWrapper: function(inst) { // value="" should make a value attribute (#6219) var props = inst._currentElement.props; if (props.value != null) { var node = ReactDOMComponentTree.getNodeFromInstance(inst); node.setAttribute('value', props.value); } }, </ins> getNativeProps: function(inst, props) { var nativeProps = Object.assign({selected: undefined, children: undefined}, props);

var node = ReactDOM.findDOMNode(stub); expect(node.innerHTML).toBe('foobar'); }); <ins> it('should set attribute for empty value', function() { var container = document.createElement('div'); var option = ReactDOM.render(<option value="" />, container); expect(option.hasAttribute('value')).toBe(true); expect(option.getAttribute('value')).toBe(''); ReactDOM.render(<option value="lava" />, container); expect(option.hasAttribute('value')).toBe(true); expect(option.getAttribute('value')).toBe('lava'); }); </ins> });

var propName = propertyInfo.propertyName; // Must explicitly cast values for HAS_SIDE_EFFECTS-properties to the // property type before comparing; only `value` does and is string. <del> // Must set `value` property if it is not null and not yet set. </del> if (!propertyInfo.hasSideEffects || <del> ('' + node[propName]) !== ('' + value) || !node.hasAttribute(propertyInfo.attributeName)) { </del> <ins> ('' + node[propName]) !== ('' + value)) { </ins> // Contrary to `setAttribute`, object properties are properly // `toString`ed by IE8/9. node[propName] = value;

); } <ins> function optionPostMount() { var inst = this; ReactDOMOption.postMountWrapper(inst); } </ins> // There are so many media events, it makes sense to just // maintain a list rather than create a `trapBubbledEvent` for each var mediaEvents = {

); } break; <ins> case 'option': transaction.getReactMountReady().enqueue( optionPostMount, this ); </ins> } return mountImage;

describe('ReactDOMComponent', function() { var React; var ReactDOM; <del> var ReactDOMFeatureFlags; </del> var ReactDOMServer; beforeEach(function() { jest.resetModuleRegistry(); React = require('React'); <del> ReactDOMFeatureFlags = require('ReactDOMFeatureFlags') </del> ReactDOM = require('ReactDOM'); ReactDOMServer = require('ReactDOMServer'); });

expect(nodeValueSetter.mock.calls.length).toBe(expected); } <del> if (ReactDOMFeatureFlags.useCreateElement) { renderWithValueAndExpect(undefined, 0); renderWithValueAndExpect('', 1); renderWithValueAndExpect('foo', 2); renderWithValueAndExpect('foo', 2); renderWithValueAndExpect(undefined, 3); renderWithValueAndExpect(null, 3); renderWithValueAndExpect('', 4); renderWithValueAndExpect(undefined, 4); } else { renderWithValueAndExpect(undefined, 0); // This differs because we will have created a node with the value // attribute set. This means it will hasAttribute, so we won't try to // set the value. renderWithValueAndExpect('', 0); renderWithValueAndExpect('foo', 1); renderWithValueAndExpect('foo', 1); renderWithValueAndExpect(undefined, 2); renderWithValueAndExpect(null, 2); // Again, much like the initial update case, we will always have the // attribute set so we won't set the value. renderWithValueAndExpect('', 2); renderWithValueAndExpect(undefined, 2); } </del> <ins> renderWithValueAndExpect(undefined, 0); renderWithValueAndExpect('', 0); renderWithValueAndExpect('foo', 1); renderWithValueAndExpect('foo', 1); renderWithValueAndExpect(undefined, 2); renderWithValueAndExpect(null, 2); renderWithValueAndExpect('', 2); renderWithValueAndExpect(undefined, 2); </ins> }); it('should not incur unnecessary DOM mutations for boolean properties', function() {