mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
d547374847
Log the time it takes to perform all DOM operations
228 lines
7.1 KiB
JavaScript
228 lines
7.1 KiB
JavaScript
/**
|
|
* Copyright 2013 Facebook, Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
* @providesModule ReactDOMIDOperations
|
|
* @typechecks static-only
|
|
*/
|
|
|
|
/*jslint evil: true */
|
|
|
|
"use strict";
|
|
|
|
var CSSPropertyOperations = require('CSSPropertyOperations');
|
|
var DOMChildrenOperations = require('DOMChildrenOperations');
|
|
var DOMPropertyOperations = require('DOMPropertyOperations');
|
|
var ReactMount = require('ReactMount');
|
|
var ReactPerf = require('ReactPerf');
|
|
|
|
var getTextContentAccessor = require('getTextContentAccessor');
|
|
var invariant = require('invariant');
|
|
|
|
/**
|
|
* Errors for properties that should not be updated with `updatePropertyById()`.
|
|
*
|
|
* @type {object}
|
|
* @private
|
|
*/
|
|
var INVALID_PROPERTY_ERRORS = {
|
|
dangerouslySetInnerHTML:
|
|
'`dangerouslySetInnerHTML` must be set using `updateInnerHTMLByID()`.',
|
|
style: '`style` must be set using `updateStylesByID()`.'
|
|
};
|
|
|
|
/**
|
|
* The DOM property to use when setting text content.
|
|
*
|
|
* @type {string}
|
|
* @private
|
|
*/
|
|
var textContentAccessor = getTextContentAccessor();
|
|
|
|
var useWhitespaceWorkaround;
|
|
|
|
/**
|
|
* Operations used to process updates to DOM nodes. This is made injectable via
|
|
* `ReactComponent.BackendIDOperations`.
|
|
*/
|
|
var ReactDOMIDOperations = {
|
|
|
|
/**
|
|
* Updates a DOM node with new property values. This should only be used to
|
|
* update DOM properties in `DOMProperty`.
|
|
*
|
|
* @param {string} id ID of the node to update.
|
|
* @param {string} name A valid property name, see `DOMProperty`.
|
|
* @param {*} value New value of the property.
|
|
* @internal
|
|
*/
|
|
updatePropertyByID: ReactPerf.measure(
|
|
'ReactDOMIDOperations',
|
|
'updatePropertyByID',
|
|
function(id, name, value) {
|
|
var node = ReactMount.getNode(id);
|
|
invariant(
|
|
!INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
|
|
'updatePropertyByID(...): %s',
|
|
INVALID_PROPERTY_ERRORS[name]
|
|
);
|
|
|
|
// If we're updating to null or undefined, we should remove the property
|
|
// from the DOM node instead of inadvertantly setting to a string. This
|
|
// brings us in line with the same behavior we have on initial render.
|
|
if (value != null) {
|
|
DOMPropertyOperations.setValueForProperty(node, name, value);
|
|
} else {
|
|
DOMPropertyOperations.deleteValueForProperty(node, name);
|
|
}
|
|
}
|
|
),
|
|
|
|
/**
|
|
* 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: ReactPerf.measure(
|
|
'ReactDOMIDOperations',
|
|
'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: ReactPerf.measure(
|
|
'ReactDOMIDOperations',
|
|
'updateStylesByID',
|
|
function(id, styles) {
|
|
var node = ReactMount.getNode(id);
|
|
CSSPropertyOperations.setValueForStyles(node, styles);
|
|
}
|
|
),
|
|
|
|
/**
|
|
* Updates a DOM node's innerHTML.
|
|
*
|
|
* @param {string} id ID of the node to update.
|
|
* @param {string} html An HTML string.
|
|
* @internal
|
|
*/
|
|
updateInnerHTMLByID: ReactPerf.measure(
|
|
'ReactDOMIDOperations',
|
|
'updateInnerHTMLByID',
|
|
function(id, html) {
|
|
var node = ReactMount.getNode(id);
|
|
|
|
// IE8: When updating a just created node with innerHTML only leading
|
|
// whitespace is removed. When updating an existing node with innerHTML
|
|
// whitespace in root TextNodes is also collapsed.
|
|
// @see quirksmode.org/bugreports/archives/2004/11/innerhtml_and_t.html
|
|
|
|
if (useWhitespaceWorkaround === undefined) {
|
|
// Feature detection; only IE8 is known to behave improperly like this.
|
|
var temp = document.createElement('div');
|
|
temp.innerHTML = ' ';
|
|
useWhitespaceWorkaround = temp.innerHTML === '';
|
|
}
|
|
|
|
if (useWhitespaceWorkaround) {
|
|
// Magic theory: IE8 supposedly differentiates between added and updated
|
|
// nodes when processing innerHTML, innerHTML on updated nodes suffers
|
|
// from worse whitespace behavior. Re-adding a node like this triggers
|
|
// the initial and more favorable whitespace behavior.
|
|
node.parentNode.replaceChild(node, node);
|
|
}
|
|
|
|
if (useWhitespaceWorkaround && html.match(/^[ \r\n\t\f]/)) {
|
|
// Recover leading whitespace by temporarily prepending any character.
|
|
// \uFEFF has the potential advantage of being zero-width/invisible.
|
|
node.innerHTML = '\uFEFF' + html;
|
|
node.firstChild.deleteData(0, 1);
|
|
} else {
|
|
node.innerHTML = html;
|
|
}
|
|
}
|
|
),
|
|
|
|
/**
|
|
* 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: ReactPerf.measure(
|
|
'ReactDOMIDOperations',
|
|
'updateTextContentByID',
|
|
function(id, content) {
|
|
var node = ReactMount.getNode(id);
|
|
node[textContentAccessor] = content;
|
|
}
|
|
),
|
|
|
|
/**
|
|
* Replaces a DOM node that exists in the document with markup.
|
|
*
|
|
* @param {string} id ID of child to be replaced.
|
|
* @param {string} markup Dangerous markup to inject in place of child.
|
|
* @internal
|
|
* @see {Danger.dangerouslyReplaceNodeWithMarkup}
|
|
*/
|
|
dangerouslyReplaceNodeWithMarkupByID: ReactPerf.measure(
|
|
'ReactDOMIDOperations',
|
|
'dangerouslyReplaceNodeWithMarkupByID',
|
|
function(id, markup) {
|
|
var node = ReactMount.getNode(id);
|
|
DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup(node, markup);
|
|
}
|
|
),
|
|
|
|
/**
|
|
* Updates a component's children by processing a series of updates.
|
|
*
|
|
* @param {array<object>} updates List of update configurations.
|
|
* @param {array<string>} markup List of markup strings.
|
|
* @internal
|
|
*/
|
|
dangerouslyProcessChildrenUpdates: ReactPerf.measure(
|
|
'ReactDOMIDOperations',
|
|
'dangerouslyProcessChildrenUpdates',
|
|
function(updates, markup) {
|
|
for (var i = 0; i < updates.length; i++) {
|
|
updates[i].parentNode = ReactMount.getNode(updates[i].parentID);
|
|
}
|
|
DOMChildrenOperations.processUpdates(updates, markup);
|
|
}
|
|
)
|
|
};
|
|
|
|
module.exports = ReactDOMIDOperations;
|