diff --git a/src/renderers/dom/client/ReactDOMIDOperations.js b/src/renderers/dom/client/ReactDOMIDOperations.js index bec8d3e619..65b01b1e67 100644 --- a/src/renderers/dom/client/ReactDOMIDOperations.js +++ b/src/renderers/dom/client/ReactDOMIDOperations.js @@ -12,7 +12,6 @@ 'use strict'; -var CSSPropertyOperations = require('CSSPropertyOperations'); var DOMChildrenOperations = require('DOMChildrenOperations'); var DOMPropertyOperations = require('DOMPropertyOperations'); var ReactMount = require('ReactMount'); @@ -33,8 +32,7 @@ var INVALID_PROPERTY_ERRORS = { }; /** - * Operations used to process updates to DOM nodes. This is made injectable via - * `ReactDOMComponent.BackendIDOperations`. + * Operations used to process updates to DOM nodes. */ var ReactDOMIDOperations = { @@ -65,67 +63,6 @@ var ReactDOMIDOperations = { } }, - /** - * Updates a DOM node with new property values. - * - * @param {string} id ID of the node to update. - * @param {string} name A valid property name. - * @param {*} value New value of the property. - * @internal - */ - updateAttributeByID: function(id, name, value) { - var node = ReactMount.getNode(id); - invariant( - !INVALID_PROPERTY_ERRORS.hasOwnProperty(name), - 'updatePropertyByID(...): %s', - INVALID_PROPERTY_ERRORS[name] - ); - DOMPropertyOperations.setValueForAttribute(node, name, value); - }, - - /** - * Updates a DOM node to remove a property. This should only be used to remove - * DOM properties in `DOMProperty`. - * - * @param {string} id ID of the node to update. - * @param {string} name A property name to remove, see `DOMProperty`. - * @internal - */ - deletePropertyByID: function(id, name, value) { - var node = ReactMount.getNode(id); - invariant( - !INVALID_PROPERTY_ERRORS.hasOwnProperty(name), - 'updatePropertyByID(...): %s', - INVALID_PROPERTY_ERRORS[name] - ); - DOMPropertyOperations.deleteValueForProperty(node, name, value); - }, - - /** - * Updates a DOM node with new style values. If a value is specified as '', - * the corresponding style property will be unset. - * - * @param {string} id ID of the node to update. - * @param {object} styles Mapping from styles to values. - * @internal - */ - updateStylesByID: function(id, styles) { - var node = ReactMount.getNode(id); - CSSPropertyOperations.setValueForStyles(node, styles); - }, - - /** - * Updates a DOM node's text content set by `props.content`. - * - * @param {string} id ID of the node to update. - * @param {string} content Text content. - * @internal - */ - updateTextContentByID: function(id, content) { - var node = ReactMount.getNode(id); - DOMChildrenOperations.updateTextContent(node, content); - }, - /** * Replaces a DOM node that exists in the document with markup. * @@ -156,9 +93,6 @@ var ReactDOMIDOperations = { ReactPerf.measureMethods(ReactDOMIDOperations, 'ReactDOMIDOperations', { updatePropertyByID: 'updatePropertyByID', - deletePropertyByID: 'deletePropertyByID', - updateStylesByID: 'updateStylesByID', - updateTextContentByID: 'updateTextContentByID', dangerouslyReplaceNodeWithMarkupByID: 'dangerouslyReplaceNodeWithMarkupByID', dangerouslyProcessChildrenUpdates: 'dangerouslyProcessChildrenUpdates', }); diff --git a/src/renderers/dom/client/ReactMount.js b/src/renderers/dom/client/ReactMount.js index c505d0dd67..0a34823e7f 100644 --- a/src/renderers/dom/client/ReactMount.js +++ b/src/renderers/dom/client/ReactMount.js @@ -14,6 +14,7 @@ var DOMProperty = require('DOMProperty'); var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter'); var ReactCurrentOwner = require('ReactCurrentOwner'); +var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags'); var ReactElement = require('ReactElement'); var ReactEmptyComponent = require('ReactEmptyComponent'); var ReactInstanceHandles = require('ReactInstanceHandles'); @@ -24,6 +25,7 @@ var ReactReconciler = require('ReactReconciler'); var ReactUpdateQueue = require('ReactUpdateQueue'); var ReactUpdates = require('ReactUpdates'); +var assign = require('Object.assign'); var emptyObject = require('emptyObject'); var containsNode = require('containsNode'); var instantiateReactComponent = require('instantiateReactComponent'); @@ -42,6 +44,10 @@ var ELEMENT_NODE_TYPE = 1; var DOC_NODE_TYPE = 9; var DOCUMENT_FRAGMENT_NODE_TYPE = 11; +var ownerDocumentContextKey = + '__ReactMount_ownerDocument$' + Math.random().toString(36).slice(2); + + /** Mapping from reactRootID to React component instance. */ var instancesByReactRootID = {}; @@ -264,6 +270,14 @@ function mountComponentIntoNode( shouldReuseMarkup, context ) { + if (ReactDOMFeatureFlags.useCreateElement) { + context = assign({}, context); + if (container.nodeType === DOC_NODE_TYPE) { + context[ownerDocumentContextKey] = container; + } else { + context[ownerDocumentContextKey] = container.ownerDocument; + } + } if (__DEV__) { if (context === emptyObject) { context = {}; @@ -276,7 +290,12 @@ function mountComponentIntoNode( componentInstance, rootID, transaction, context ); componentInstance._renderedComponent._topLevelWrapper = componentInstance; - ReactMount._mountImageIntoNode(markup, container, shouldReuseMarkup); + ReactMount._mountImageIntoNode( + markup, + container, + shouldReuseMarkup, + transaction + ); } /** @@ -294,7 +313,9 @@ function batchedMountComponentIntoNode( shouldReuseMarkup, context ) { - var transaction = ReactUpdates.ReactReconcileTransaction.getPooled(); + var transaction = ReactUpdates.ReactReconcileTransaction.getPooled( + /* forceHTML */ shouldReuseMarkup + ); transaction.perform( mountComponentIntoNode, null, @@ -870,7 +891,12 @@ var ReactMount = { ); }, - _mountImageIntoNode: function(markup, container, shouldReuseMarkup) { + _mountImageIntoNode: function( + markup, + container, + shouldReuseMarkup, + transaction + ) { invariant( container && ( container.nodeType === ELEMENT_NODE_TYPE || @@ -959,9 +985,18 @@ var ReactMount = { 'See React.renderToString() for server rendering.' ); - setInnerHTML(container, markup); + if (transaction.useCreateElement) { + while (container.lastChild) { + container.removeChild(container.lastChild); + } + container.appendChild(markup); + } else { + setInnerHTML(container, markup); + } }, + ownerDocumentContextKey: ownerDocumentContextKey, + /** * React ID utilities. */ diff --git a/src/renderers/dom/client/ReactReconcileTransaction.js b/src/renderers/dom/client/ReactReconcileTransaction.js index 086f30fa7a..51b70ee179 100644 --- a/src/renderers/dom/client/ReactReconcileTransaction.js +++ b/src/renderers/dom/client/ReactReconcileTransaction.js @@ -15,6 +15,7 @@ var CallbackQueue = require('CallbackQueue'); var PooledClass = require('PooledClass'); var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter'); +var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags'); var ReactInputSelection = require('ReactInputSelection'); var Transaction = require('Transaction'); @@ -106,7 +107,7 @@ var TRANSACTION_WRAPPERS = [ * * @class ReactReconcileTransaction */ -function ReactReconcileTransaction() { +function ReactReconcileTransaction(forceHTML) { this.reinitializeTransaction(); // Only server-side rendering really needs this option (see // `ReactServerRendering`), but server-side uses @@ -115,6 +116,8 @@ function ReactReconcileTransaction() { // `ReactTextComponent` checks it in `mountComponent`.` this.renderToStaticMarkup = false; this.reactMountReady = CallbackQueue.getPooled(null); + this.useCreateElement = + !forceHTML && ReactDOMFeatureFlags.useCreateElement; } var Mixin = { diff --git a/src/renderers/dom/client/utils/DOMChildrenOperations.js b/src/renderers/dom/client/utils/DOMChildrenOperations.js index ad6bea4057..0d4d4003ac 100644 --- a/src/renderers/dom/client/utils/DOMChildrenOperations.js +++ b/src/renderers/dom/client/utils/DOMChildrenOperations.js @@ -98,7 +98,13 @@ var DOMChildrenOperations = { } } - var renderedMarkup = Danger.dangerouslyRenderMarkup(markupList); + var renderedMarkup; + // markupList is either a list of markup or just a list of elements + if (markupList.length && typeof markupList[0] === 'string') { + renderedMarkup = Danger.dangerouslyRenderMarkup(markupList); + } else { + renderedMarkup = markupList; + } // Remove updated children first so that `toIndex` is consistent. if (updatedChildren) { diff --git a/src/renderers/dom/client/wrappers/__tests__/ReactDOMTextarea-test.js b/src/renderers/dom/client/wrappers/__tests__/ReactDOMTextarea-test.js index 91894b6221..c4b7c38a21 100644 --- a/src/renderers/dom/client/wrappers/__tests__/ReactDOMTextarea-test.js +++ b/src/renderers/dom/client/wrappers/__tests__/ReactDOMTextarea-test.js @@ -62,7 +62,7 @@ describe('ReactDOMTextarea', function() { }); it('should display "false" for `defaultValue` of `false`', function() { - var stub =