Convert ReactDOMTextarea to not be a wrapper

This commit is contained in:
Ben Alpert
2015-06-04 13:08:31 -07:00
parent e04015a4a2
commit d2e7e56cc4
4 changed files with 69 additions and 70 deletions
@@ -11,7 +11,6 @@
'use strict';
var AutoFocusUtils = require('AutoFocusUtils');
var ReactDOMIDOperations = require('ReactDOMIDOperations');
var LinkedValueUtils = require('LinkedValueUtils');
var ReactMount = require('ReactMount');
@@ -78,15 +77,6 @@ var ReactDOMInput = {
instancesByReactID[inst._rootNodeID] = inst;
},
postMountWrapper: function(inst, transaction, props) {
if (props.autoFocus) {
transaction.getReactMountReady().enqueue(
AutoFocusUtils.focusDOMComponent,
inst
);
}
},
unmountWrapper: function(inst) {
delete instancesByReactID[inst._rootNodeID];
},
@@ -11,26 +11,18 @@
'use strict';
var AutoFocusUtils = require('AutoFocusUtils');
var DOMPropertyOperations = require('DOMPropertyOperations');
var LinkedValueUtils = require('LinkedValueUtils');
var ReactBrowserComponentMixin = require('ReactBrowserComponentMixin');
var ReactClass = require('ReactClass');
var ReactElement = require('ReactElement');
var ReactInstanceMap = require('ReactInstanceMap');
var ReactDOMIDOperations = require('ReactDOMIDOperations');
var ReactUpdates = require('ReactUpdates');
var assign = require('Object.assign');
var findDOMNode = require('findDOMNode');
var invariant = require('invariant');
var warning = require('warning');
var textarea = ReactElement.createFactory('textarea');
function forceUpdateIfMounted() {
if (this.isMounted()) {
this.forceUpdate();
if (this._rootNodeID) {
// DOM component is still mounted; update
ReactDOMTextarea.updateWrapper(this);
}
}
@@ -49,24 +41,35 @@ function forceUpdateIfMounted() {
* The rendered element will be initialized with an empty value, the prop
* `defaultValue` if specified, or the children content (deprecated).
*/
var ReactDOMTextarea = ReactClass.createClass({
displayName: 'ReactDOMTextarea',
tagName: 'TEXTAREA',
mixins: [AutoFocusUtils.Mixin, ReactBrowserComponentMixin],
componentWillMount: function() {
LinkedValueUtils.checkPropTypes(
'textarea',
this.props,
ReactInstanceMap.get(this)._currentElement._owner
var ReactDOMTextarea = {
getNativeProps: function(inst, props, context) {
invariant(
props.dangerouslySetInnerHTML == null,
'`dangerouslySetInnerHTML` does not make sense on <textarea>.'
);
// Always set children to the same thing. In IE9, the selection range will
// get reset if `textContent` is mutated.
var nativeProps = assign({}, props, {
defaultValue: undefined,
value: undefined,
children: inst._wrapperState.initialValue,
onChange: inst._wrapperState.onChange,
});
return nativeProps;
},
getInitialState: function() {
var defaultValue = this.props.defaultValue;
mountWrapper: function(inst, props) {
LinkedValueUtils.checkPropTypes(
'textarea',
props,
inst._currentElement._owner
);
var defaultValue = props.defaultValue;
// TODO (yungsters): Remove support for children content in <textarea>.
var children = this.props.children;
var children = props.children;
if (children != null) {
if (__DEV__) {
warning(
@@ -92,50 +95,38 @@ var ReactDOMTextarea = ReactClass.createClass({
if (defaultValue == null) {
defaultValue = '';
}
var value = LinkedValueUtils.getValue(this.props);
return {
var value = LinkedValueUtils.getValue(props);
inst._wrapperState = {
// We save the initial value so that `ReactDOMComponent` doesn't update
// `textContent` (unnecessary since we update value).
// The initial value can be a boolean or object so that's why it's
// forced to be a string.
initialValue: '' + (value != null ? value : defaultValue),
onChange: _handleChange.bind(inst),
};
},
render: function() {
// Clone `this.props` so we don't mutate the input.
var props = assign({}, this.props);
invariant(
props.dangerouslySetInnerHTML == null,
'`dangerouslySetInnerHTML` does not make sense on <textarea>.'
);
props.defaultValue = null;
props.value = null;
props.onChange = this._handleChange;
// Always set children to the same thing. In IE9, the selection range will
// get reset if `textContent` is mutated.
return textarea(props, this.state.initialValue);
},
componentDidUpdate: function(prevProps, prevState, prevContext) {
var value = LinkedValueUtils.getValue(this.props);
updateWrapper: function(inst) {
var props = inst._currentElement.props;
var value = LinkedValueUtils.getValue(props);
if (value != null) {
var rootNode = findDOMNode(this);
// Cast `value` to a string to ensure the value is set correctly. While
// browsers typically do this as necessary, jsdom doesn't.
DOMPropertyOperations.setValueForProperty(rootNode, 'value', '' + value);
ReactDOMIDOperations.updatePropertyByID(
inst._rootNodeID,
'value',
'' + value
);
}
},
};
_handleChange: function(event) {
var returnValue = LinkedValueUtils.executeOnChange(this.props, event);
ReactUpdates.asap(forceUpdateIfMounted, this);
return returnValue;
},
});
function _handleChange(event) {
var props = this._currentElement.props;
var returnValue = LinkedValueUtils.executeOnChange(props, event);
ReactUpdates.asap(forceUpdateIfMounted, this);
return returnValue;
}
module.exports = ReactDOMTextarea;
+21 -1
View File
@@ -14,6 +14,7 @@
'use strict';
var AutoFocusUtils = require('AutoFocusUtils');
var CSSPropertyOperations = require('CSSPropertyOperations');
var DOMProperty = require('DOMProperty');
var DOMPropertyOperations = require('DOMPropertyOperations');
@@ -21,6 +22,7 @@ var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
var ReactComponentBrowserEnvironment =
require('ReactComponentBrowserEnvironment');
var ReactDOMInput = require('ReactDOMInput');
var ReactDOMTextarea = require('ReactDOMTextarea');
var ReactMount = require('ReactMount');
var ReactMultiChild = require('ReactMultiChild');
var ReactPerf = require('ReactPerf');
@@ -286,6 +288,10 @@ ReactDOMComponent.Mixin = {
ReactDOMInput.mountWrapper(this, props);
props = ReactDOMInput.getNativeProps(this, props, context);
break;
case 'textarea':
ReactDOMTextarea.mountWrapper(this, props);
props = ReactDOMTextarea.getNativeProps(this, props, context);
break;
}
assertValidProps(this, props);
@@ -304,7 +310,13 @@ ReactDOMComponent.Mixin = {
switch (this._tag) {
case 'input':
ReactDOMInput.postMountWrapper(this, transaction, props);
case 'textarea':
if (props.autoFocus) {
transaction.getReactMountReady().enqueue(
AutoFocusUtils.focusDOMComponent,
this
);
}
break;
}
@@ -458,6 +470,11 @@ ReactDOMComponent.Mixin = {
lastProps = ReactDOMInput.getNativeProps(this, lastProps);
nextProps = ReactDOMInput.getNativeProps(this, nextProps);
break;
case 'textarea':
ReactDOMTextarea.updateWrapper(this);
lastProps = ReactDOMTextarea.getNativeProps(this, lastProps);
nextProps = ReactDOMTextarea.getNativeProps(this, nextProps);
break;
}
assertValidProps(this, nextProps);
@@ -656,6 +673,9 @@ ReactDOMComponent.Mixin = {
case 'input':
ReactDOMInput.unmountWrapper(this);
break;
case 'textarea':
ReactDOMTextarea.unmountWrapper(this);
break;
case 'html':
case 'head':
case 'body':
@@ -31,7 +31,6 @@ var ReactDOMIDOperations = require('ReactDOMIDOperations');
var ReactDOMIframe = require('ReactDOMIframe');
var ReactDOMOption = require('ReactDOMOption');
var ReactDOMSelect = require('ReactDOMSelect');
var ReactDOMTextarea = require('ReactDOMTextarea');
var ReactDOMTextComponent = require('ReactDOMTextComponent');
var ReactElement = require('ReactElement');
var ReactEventListener = require('ReactEventListener');
@@ -117,7 +116,6 @@ function inject() {
'img': ReactDOMImg,
'option': ReactDOMOption,
'select': ReactDOMSelect,
'textarea': ReactDOMTextarea,
});
ReactInjection.DOMProperty.injectDOMPropertyConfig(HTMLDOMPropertyConfig);