Пример #1
0
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);
      }
    }
  }
}
Пример #2
0
 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);
 },
Пример #3
0
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);
      }
    }
  }
}
Пример #4
0
 _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
     );
   }
 },
Пример #5
0
 _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,
     );
   }
 },
Пример #6
0
/**
 * 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.
    );
  }
}
Пример #7
0
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);
    }
  }
}