function setInitialDOMProperties( domElement : Element, rootContainerElement : Element, nextProps : Object, isCustomComponentTag : boolean, ) : void { for (var propKey in nextProps) { var nextProp = nextProps[propKey]; if (!nextProps.hasOwnProperty(propKey)) { continue; } if (propKey === STYLE) { if (__DEV__) { if (nextProp) { // Freeze the next style object so that we can assume it won't be // mutated. We have already warned for this in the past. Object.freeze(nextProp); } } // Relies on `updateStylesByID` not mutating `styleUpdates`. // TODO: call ReactInstrumentation.debugTool.onHostOperation in DEV. CSSPropertyOperations.setValueForStyles( domElement, nextProp, ); } else if (propKey === DANGEROUSLY_SET_INNER_HTML) { var nextHtml = nextProp ? nextProp[HTML] : undefined; if (nextHtml != null) { setInnerHTML(domElement, nextHtml); } } else if (propKey === CHILDREN) { if (typeof nextProp === 'string') { setTextContent(domElement, nextProp); } else if (typeof nextProp === 'number') { setTextContent(domElement, '' + nextProp); } } else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING) { // Noop } else if (registrationNameModules.hasOwnProperty(propKey)) { if (nextProp) { ensureListeningTo(rootContainerElement, propKey); } } else if (isCustomComponentTag) { DOMPropertyOperations.setValueForAttribute( domElement, propKey, nextProp ); } else if ( DOMProperty.properties[propKey] || DOMProperty.isCustomAttribute(propKey)) { // If we're updating to null or undefined, we should remove the property // from the DOM node instead of inadvertently setting to a string. This // brings us in line with the same behavior we have on initial render. if (nextProp != null) { DOMPropertyOperations.setValueForProperty(domElement, propKey, nextProp); } } } }
function updateDOMProperties( domElement : Element, updatePayload : Array<any>, wasCustomComponentTag : boolean, isCustomComponentTag : boolean, ) : void { // TODO: Handle wasCustomComponentTag for (var i = 0; i < updatePayload.length; i += 2) { var propKey = updatePayload[i]; var propValue = updatePayload[i + 1]; if (propKey === STYLE) { // TODO: call ReactInstrumentation.debugTool.onHostOperation in DEV. CSSPropertyOperations.setValueForStyles( domElement, propValue, ); } else if (propKey === DANGEROUSLY_SET_INNER_HTML) { setInnerHTML(domElement, propValue); } else if (propKey === CHILDREN) { setTextContent(domElement, propValue); } else if (isCustomComponentTag) { if (propValue != null) { DOMPropertyOperations.setValueForAttribute( domElement, propKey, propValue ); } else { DOMPropertyOperations.deleteValueForAttribute( domElement, propKey ); } } else if ( DOMProperty.properties[propKey] || DOMProperty.isCustomAttribute(propKey)) { // If we're updating to null or undefined, we should remove the property // from the DOM node instead of inadvertently setting to a string. This // brings us in line with the same behavior we have on initial render. if (propValue != null) { DOMPropertyOperations.setValueForProperty(domElement, propKey, propValue); } else { DOMPropertyOperations.deleteValueForProperty(domElement, propKey); } } } }
_updateDOMProperties: function(lastProps, nextProps, transaction) { var propKey; var styleName; var styleUpdates; for (propKey in lastProps) { if (nextProps.hasOwnProperty(propKey) || !lastProps.hasOwnProperty(propKey) || lastProps[propKey] == null) { continue; } if (propKey === STYLE) { var lastStyle = this._previousStyleCopy; for (styleName in lastStyle) { if (lastStyle.hasOwnProperty(styleName)) { styleUpdates = styleUpdates || {}; styleUpdates[styleName] = ''; } } this._previousStyleCopy = null; } else if (registrationNameModules.hasOwnProperty(propKey)) { if (lastProps[propKey]) { // Only call deleteListener if there was a listener previously or // else willDeleteListener gets called when there wasn't actually a // listener (e.g., onClick={null}) deleteListener(this, propKey); } } else if (this._namespaceURI === DOMNamespaces.svg) { DOMPropertyOperations.deleteValueForSVGAttribute( getNode(this), propKey ); } else if ( DOMProperty.properties[propKey] || DOMProperty.isCustomAttribute(propKey)) { DOMPropertyOperations.deleteValueForProperty(getNode(this), propKey); } } for (propKey in nextProps) { var nextProp = nextProps[propKey]; var lastProp = propKey === STYLE ? this._previousStyleCopy : lastProps != null ? lastProps[propKey] : undefined; if (!nextProps.hasOwnProperty(propKey) || nextProp === lastProp || nextProp == null && lastProp == null) { continue; } if (propKey === STYLE) { if (nextProp) { if (__DEV__) { checkAndWarnForMutatedStyle( this._previousStyleCopy, this._previousStyle, this ); this._previousStyle = nextProp; } nextProp = this._previousStyleCopy = assign({}, nextProp); } else { this._previousStyleCopy = null; } if (lastProp) { // Unset styles on `lastProp` but not on `nextProp`. for (styleName in lastProp) { if (lastProp.hasOwnProperty(styleName) && (!nextProp || !nextProp.hasOwnProperty(styleName))) { styleUpdates = styleUpdates || {}; styleUpdates[styleName] = ''; } } // Update styles that changed since `lastProp`. for (styleName in nextProp) { if (nextProp.hasOwnProperty(styleName) && lastProp[styleName] !== nextProp[styleName]) { styleUpdates = styleUpdates || {}; styleUpdates[styleName] = nextProp[styleName]; } } } else { // Relies on `updateStylesByID` not mutating `styleUpdates`. styleUpdates = nextProp; } } else if (registrationNameModules.hasOwnProperty(propKey)) { if (nextProp) { enqueuePutListener(this, propKey, nextProp, transaction); } else if (lastProp) { deleteListener(this, propKey); } } else if (isCustomComponent(this._tag, nextProps)) { if (!RESERVED_PROPS.hasOwnProperty(propKey)) { DOMPropertyOperations.setValueForAttribute( getNode(this), propKey, nextProp ); } } else if (this._namespaceURI === DOMNamespaces.svg) { if (!RESERVED_PROPS.hasOwnProperty(propKey)) { DOMPropertyOperations.setValueForSVGAttribute( getNode(this), propKey, nextProp ); } } else if ( DOMProperty.properties[propKey] || DOMProperty.isCustomAttribute(propKey)) { var node = getNode(this); // If we're updating to null or undefined, we should remove the property // from the DOM node instead of inadvertently setting to a string. This // brings us in line with the same behavior we have on initial render. if (nextProp != null) { DOMPropertyOperations.setValueForProperty(node, propKey, nextProp); } else { DOMPropertyOperations.deleteValueForProperty(node, propKey); } } } if (styleUpdates) { CSSPropertyOperations.setValueForStyles( getNode(this), styleUpdates, this ); } },
updateStylesByID: function(id, styles) { var node = ReactMount.getNode(id); CSSPropertyOperations.setValueForStyles(node, styles); },
_updateDOMProperties: function( lastProps, nextProps, transaction, isCustomComponentTag, ) { var propKey; var styleName; var styleUpdates; for (propKey in lastProps) { if ( nextProps.hasOwnProperty(propKey) || !lastProps.hasOwnProperty(propKey) || lastProps[propKey] == null ) { continue; } if (propKey === STYLE) { var lastStyle = lastProps[STYLE]; for (styleName in lastStyle) { if (lastStyle.hasOwnProperty(styleName)) { styleUpdates = styleUpdates || {}; styleUpdates[styleName] = ''; } } } else if (registrationNameModules.hasOwnProperty(propKey)) { // Do nothing for event names. } else if (!DOMProperty.isReservedProp(propKey)) { if (isCustomComponent(this._tag, lastProps)) { DOMPropertyOperations.deleteValueForAttribute(getNode(this), propKey); } else { DOMPropertyOperations.deleteValueForProperty(getNode(this), propKey); } } } for (propKey in nextProps) { var nextProp = nextProps[propKey]; var lastProp = lastProps != null ? lastProps[propKey] : undefined; if ( !nextProps.hasOwnProperty(propKey) || nextProp === lastProp || (nextProp == null && lastProp == null) ) { continue; } if (propKey === STYLE) { if (nextProp) { if (__DEV__) { Object.freeze(nextProp); } } if (lastProp) { // Unset styles on `lastProp` but not on `nextProp`. for (styleName in lastProp) { if ( lastProp.hasOwnProperty(styleName) && (!nextProp || !nextProp.hasOwnProperty(styleName)) ) { styleUpdates = styleUpdates || {}; styleUpdates[styleName] = ''; } } // Update styles that changed since `lastProp`. for (styleName in nextProp) { if ( nextProp.hasOwnProperty(styleName) && lastProp[styleName] !== nextProp[styleName] ) { styleUpdates = styleUpdates || {}; styleUpdates[styleName] = nextProp[styleName]; } } } else { // Relies on `updateStylesByID` not mutating `styleUpdates`. styleUpdates = nextProp; } } else if (registrationNameModules.hasOwnProperty(propKey)) { if (nextProp) { ensureListeningTo(this, propKey, transaction); } } else if (isCustomComponentTag) { if (!DOMProperty.isReservedProp(propKey)) { DOMPropertyOperations.setValueForAttribute( getNode(this), propKey, nextProp, ); } } else if (!DOMProperty.isReservedProp(propKey)) { var node = getNode(this); // If we're updating to null or undefined, we should remove the property // from the DOM node instead of inadvertently setting to a string. This // brings us in line with the same behavior we have on initial render. if (nextProp != null) { DOMPropertyOperations.setValueForProperty(node, propKey, nextProp); } else { DOMPropertyOperations.deleteValueForProperty(node, propKey); } } } if (styleUpdates) { if (__DEV__) { ReactInstrumentation.debugTool.onHostOperation({ instanceID: this._debugID, type: 'update styles', payload: styleUpdates, }); } CSSPropertyOperations.setValueForStyles( getNode(this), styleUpdates, this, ); } },
/** * Reconciles the properties by detecting differences in property values and * updating the DOM as necessary. This function is probably the single most * critical path for performance optimization. * * TODO: Benchmark whether checking for changed values in memory actually * improves performance (especially statically positioned elements). * TODO: Benchmark the effects of putting this at the top since 99% of props * do not change for a given reconciliation. * TODO: Benchmark areas that can be improved with caching. */ function updateDOMProperties( domElement : Element, rootContainerElement : Element, lastProps : null | Object, nextProps : Object, wasCustomComponentTag : boolean, isCustomComponentTag : boolean, ) : void { var propKey; var styleName; var styleUpdates; for (propKey in lastProps) { if (nextProps.hasOwnProperty(propKey) || !lastProps.hasOwnProperty(propKey) || lastProps[propKey] == null) { continue; } if (propKey === STYLE) { var lastStyle = lastProps[propKey]; for (styleName in lastStyle) { if (lastStyle.hasOwnProperty(styleName)) { styleUpdates = styleUpdates || {}; styleUpdates[styleName] = ''; } } } else if (propKey === DANGEROUSLY_SET_INNER_HTML || propKey === CHILDREN) { // TODO: Clear innerHTML. This is currently broken in Fiber because we are // too late to clear everything at this point because new children have // already been inserted. } else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING) { // Noop } else if (registrationNameModules.hasOwnProperty(propKey)) { // Do nothing for deleted listeners. } else if (wasCustomComponentTag) { DOMPropertyOperations.deleteValueForAttribute( domElement, propKey ); } else if ( DOMProperty.properties[propKey] || DOMProperty.isCustomAttribute(propKey)) { DOMPropertyOperations.deleteValueForProperty(domElement, propKey); } } for (propKey in nextProps) { var nextProp = nextProps[propKey]; var lastProp = lastProps != null ? lastProps[propKey] : undefined; if (!nextProps.hasOwnProperty(propKey) || nextProp === lastProp || nextProp == null && lastProp == null) { continue; } if (propKey === STYLE) { if (__DEV__) { if (nextProp) { // Freeze the next style object so that we can assume it won't be // mutated. We have already warned for this in the past. Object.freeze(nextProp); } } if (lastProp) { // Unset styles on `lastProp` but not on `nextProp`. for (styleName in lastProp) { if (lastProp.hasOwnProperty(styleName) && (!nextProp || !nextProp.hasOwnProperty(styleName))) { styleUpdates = styleUpdates || {}; styleUpdates[styleName] = ''; } } // Update styles that changed since `lastProp`. for (styleName in nextProp) { if (nextProp.hasOwnProperty(styleName) && lastProp[styleName] !== nextProp[styleName]) { styleUpdates = styleUpdates || {}; styleUpdates[styleName] = nextProp[styleName]; } } } else { // Relies on `updateStylesByID` not mutating `styleUpdates`. styleUpdates = nextProp; } } else if (propKey === DANGEROUSLY_SET_INNER_HTML) { var nextHtml = nextProp ? nextProp[HTML] : undefined; var lastHtml = lastProp ? lastProp[HTML] : undefined; if (nextHtml) { if (lastHtml) { if (lastHtml !== nextHtml) { setInnerHTML(domElement, '' + nextHtml); } } else { setInnerHTML(domElement, nextHtml); } } else { // TODO: It might be too late to clear this if we have children // inserted already. } } else if (propKey === CHILDREN) { if (typeof nextProp === 'string') { setTextContent(domElement, nextProp); } else if (typeof nextProp === 'number') { setTextContent(domElement, '' + nextProp); } } else if (propKey === SUPPRESS_CONTENT_EDITABLE_WARNING) { // Noop } else if (registrationNameModules.hasOwnProperty(propKey)) { if (nextProp) { ensureListeningTo(rootContainerElement, propKey); } } else if (isCustomComponentTag) { DOMPropertyOperations.setValueForAttribute( domElement, propKey, nextProp ); } else if ( DOMProperty.properties[propKey] || DOMProperty.isCustomAttribute(propKey)) { // If we're updating to null or undefined, we should remove the property // from the DOM node instead of inadvertently setting to a string. This // brings us in line with the same behavior we have on initial render. if (nextProp != null) { DOMPropertyOperations.setValueForProperty(domElement, propKey, nextProp); } else { DOMPropertyOperations.deleteValueForProperty(domElement, propKey); } } } if (styleUpdates) { var componentPlaceholder = null; if (__DEV__) { // HACK var internalInstance = ReactDOMComponentTree.getInstanceFromNode(domElement); componentPlaceholder = { _currentElement: { type: internalInstance.type, props: internalInstance.memoizedProps }, _debugID: internalInstance._debugID, }; } CSSPropertyOperations.setValueForStyles( domElement, styleUpdates, componentPlaceholder // TODO: Change CSSPropertyOperations to use getCurrentOwnerName. ); } }
updateStylesByID: ReactPerf.measure('ReactDOMIDOperations', 'updateStylesByID', function(id, styles) { var node = ReactMount.getNode(id); CSSPropertyOperations.setValueForStyles(node, styles); }),
function setInitialDOMProperties( tag: string, domElement: Element, rootContainerElement: Element | Document, nextProps: Object, isCustomComponentTag: boolean, ): void { for (var propKey in nextProps) { if (!nextProps.hasOwnProperty(propKey)) { continue; } var nextProp = nextProps[propKey]; if (propKey === STYLE) { if (__DEV__) { if (nextProp) { // Freeze the next style object so that we can assume it won't be // mutated. We have already warned for this in the past. Object.freeze(nextProp); } } // Relies on `updateStylesByID` not mutating `styleUpdates`. CSSPropertyOperations.setValueForStyles(domElement, nextProp); } else if (propKey === DANGEROUSLY_SET_INNER_HTML) { var nextHtml = nextProp ? nextProp[HTML] : undefined; if (nextHtml != null) { setInnerHTML(domElement, nextHtml); } } else if (propKey === CHILDREN) { if (typeof nextProp === 'string') { // Avoid setting initial textContent when the text is empty. In IE11 setting // textContent on a <textarea> will cause the placeholder to not // show within the <textarea> until it has been focused and blurred again. // https://github.com/facebook/react/issues/6731#issuecomment-254874553 var canSetTextContent = tag !== 'textarea' || nextProp !== ''; if (canSetTextContent) { setTextContent(domElement, nextProp); } } else if (typeof nextProp === 'number') { setTextContent(domElement, '' + nextProp); } } else if ( propKey === SUPPRESS_CONTENT_EDITABLE_WARNING || propKey === SUPPRESS_HYDRATION_WARNING ) { // Noop } else if (registrationNameModules.hasOwnProperty(propKey)) { if (nextProp != null) { if (__DEV__ && typeof nextProp !== 'function') { warnForInvalidEventListener(propKey, nextProp); } ensureListeningTo(rootContainerElement, propKey); } } else if (isCustomComponentTag) { DOMPropertyOperations.setValueForAttribute(domElement, propKey, nextProp); } else if (nextProp != null) { // If we're updating to null or undefined, we should remove the property // from the DOM node instead of inadvertently setting to a string. This // brings us in line with the same behavior we have on initial render. DOMPropertyOperations.setValueForProperty(domElement, propKey, nextProp); } } }