示例#1
0
  findReactContainerForID: function(id) {
    var reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(id);
    var container = containersByReactRootID[reactRootID];

    if (__DEV__) {
      var rootElement = rootElementsByReactRootID[reactRootID];
      if (rootElement && rootElement.parentNode !== container) {
        invariant(
          // Call internalGetID here because getID calls isValid which calls
          // findReactContainerForID (this function).
          internalGetID(rootElement) === reactRootID,
          'ReactMount: Root element ID differed from reactRootID.'
        );

        var containerChild = container.firstChild;
        if (containerChild &&
            reactRootID === internalGetID(containerChild)) {
          // If the container has a new child with the same ID as the old
          // root element, then rootElementsByReactRootID[reactRootID] is
          // just stale and needs to be updated. The case that deserves a
          // warning is when the container is empty.
          rootElementsByReactRootID[reactRootID] = containerChild;
        } else {
          console.warn(
            'ReactMount: Root element has been removed from its original ' +
            'container. New container:', rootElement.parentNode
          );
        }
      }
    }

    return container;
  },
 function findParent(node) {
   var nodeID = ReactMount.getID(node);
   var rootID = ReactInstanceHandles.getReactRootIDFromNodeID(nodeID);
   var container = ReactMount.findReactContainerForID(rootID);
   var parent = ReactMount.getFirstReactDOM(container);
   return parent;
 }
示例#3
0
// New browsers have a path attribute on native events
function handleTopLevelWithPath(bookKeeping) {
  var path = bookKeeping.nativeEvent.path;
  var currentNativeTarget = path[0];
  for (var i = 0; i < path.length; i++) {
    var currentPathElement = path[i];
    var currentPathElementID = ReactMount.getID(currentPathElement);
    if (currentPathElement.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE) {
      currentNativeTarget = path[i + 1];
    }
    if (ReactMount.isRenderedByReact(currentPathElement)) {
      var newRootID = ReactInstanceHandles.getReactRootIDFromNodeID(
        currentPathElementID
      );
      bookKeeping.ancestors.push(currentPathElement);

      var topLevelTargetID = ReactMount.getID(currentPathElement) || '';
      ReactEventListener._handleTopLevel(
        bookKeeping.topLevelType,
        currentPathElement,
        topLevelTargetID,
        bookKeeping.nativeEvent,
        currentNativeTarget
      );

      // Jump to the root of this React render tree
      while (currentPathElementID !== newRootID) {
        i++;
        currentPathElement = path[i];
        currentPathElementID = ReactMount.getID(currentPathElement);
      }
    }
  }
}
/**
 * Finds the parent React component of `node`.
 *
 * @param {*} node
 * @return {?DOMEventTarget} Parent container, or `null` if the specified node
 *                           is not nested.
 */
function findParent(node) {
  // TODO: It may be a good idea to cache this to prevent unnecessary DOM
  // traversal, but caching is difficult to do correctly without using a
  // mutation observer to listen for all DOM changes.
  var nodeID = ReactMount.getID(node);
  var rootID = ReactInstanceHandles.getReactRootIDFromNodeID(nodeID);
  var container = ReactMount.findReactContainerForID(rootID);
  var parent = ReactMount.getFirstReactDOM(container);
  return parent;
}
示例#5
0
 registerContainer: function(container) {
   var id = getReactRootID(container);
   // If one exists, make sure it is a valid "reactRoot" ID.
   if (!id || id !== ReactInstanceHandles.getReactRootIDFromNodeID(id)) {
     // No valid "reactRoot" ID found, create one.
     id = ReactInstanceHandles.createReactRootID(
       ClientReactRootIndex.createReactRootIndex()
     );
   }
   containersByReactRootID[id] = container;
   return id;
 },
示例#6
0
 registerContainer: function(container) {
   var reactRootID = getReactRootID(container);
   if (reactRootID) {
     // If one exists, make sure it is a valid "reactRoot" ID.
     reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(reactRootID);
   }
   if (!reactRootID) {
     // No valid "reactRoot" ID found, create one.
     reactRootID = ReactInstanceHandles.createReactRootID();
   }
   containersByReactRootID[reactRootID] = container;
   return reactRootID;
 },
示例#7
0
  findReactContainerForID: function(id) {
    var reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(id);
    var container = containersByReactRootID[reactRootID];

    if (__DEV__) {
      var rootElement = rootElementsByReactRootID[reactRootID];
      if (rootElement && rootElement.parentNode !== container) {
        console.warn(
          "ReactMount: Root element has been removed from its original " +
          "container. New container:", rootElement.parentNode
        );
      }
    }

    return container;
  },
示例#8
0
/**
 * Returns the first (deepest) ancestor of a node which is rendered by this copy
 * of React.
 */
function findFirstReactDOMImpl(node) {
  // This node might be from another React instance, so we make sure not to
  // examine the node cache here
  for (; node && node.parentNode !== node; node = node.parentNode) {
    if (node.nodeType !== 1) {
      // Not a DOMElement, therefore not a React component
      continue;
    }
    var nodeID = internalGetID(node);
    if (!nodeID) {
      continue;
    }
    var reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(nodeID);

    // If containersByReactRootID contains the container we find by crawling up
    // the tree, we know that this instance of React rendered the node.
    // nb. isValid's strategy (with containsNode) does not work because render
    // trees may be nested and we don't want a false positive in that case.
    var current = node;
    var lastID;
    do {
      lastID = internalGetID(current);
      current = current.parentNode;
      if (current == null) {
        // The passed-in node has been detached from the container it was
        // originally rendered into.
        return null;
      }
    } while (lastID !== reactRootID);

    if (current === containersByReactRootID[reactRootID]) {
      return node;
    }
  }
  return null;
}
示例#9
0
 findReactContainerForID: function(id) {
   var reatRootID = ReactInstanceHandles.getReactRootIDFromNodeID(id);
   // TODO: Consider throwing if `id` is not a valid React element ID.
   return containersByReactRootID[reatRootID];
 },
 it('should support strings', function() {
   var test = '.reactRoot[s_0_1][0]..[1]';
   var expected = '.reactRoot[s_0_1]';
   var actual = ReactInstanceHandles.getReactRootIDFromNodeID(test);
   expect(actual).toEqual(expected);
 });
示例#11
0
  unmountComponentAtNode: function(container) {
    // Various parts of our code (such as ReactCompositeComponent's
    // _renderValidatedComponent) assume that calls to render aren't nested;
    // verify that that's the case. (Strictly speaking, unmounting won't cause a
    // render but we still don't expect to be in a render call here.)
    warning(
      ReactCurrentOwner.current == null,
      'unmountComponentAtNode(): Render methods should be a pure function ' +
      'of props and state; triggering nested component updates from render ' +
      'is not allowed. If necessary, trigger nested updates in ' +
      'componentDidUpdate. Check the render method of %s.',
      ReactCurrentOwner.current && ReactCurrentOwner.current.getName() ||
        'ReactCompositeComponent'
    );

    invariant(
      container && (
        container.nodeType === ELEMENT_NODE_TYPE ||
        container.nodeType === DOC_NODE_TYPE ||
        container.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE
      ),
      'unmountComponentAtNode(...): Target container is not a DOM element.'
    );

    var reactRootID = getReactRootID(container);
    var component = instancesByReactRootID[reactRootID];
    if (!component) {
      // Check if the node being unmounted was rendered by React, but isn't a
      // root node.
      var containerHasNonRootReactChild = hasNonRootReactChild(container);

      // Check if the container itself is a React root node.
      var containerID = internalGetID(container);
      var isContainerReactRoot =
          containerID &&
          containerID ===
            ReactInstanceHandles.getReactRootIDFromNodeID(containerID);

      if (__DEV__) {
        warning(
          !containerHasNonRootReactChild,
          'unmountComponentAtNode(): The node you\'re attempting to unmount ' +
          'was rendered by React and is not a top-level container. %s',
          (
            isContainerReactRoot ?
              'You may have accidentally passed in a React root node instead ' +
              'of its container.' :
              'Instead, have the parent component update its state and ' +
              'rerender in order to remove this component.'
          )
        );
      }

      return false;
    }
    ReactUpdates.batchedUpdates(
      unmountComponentFromNode,
      component,
      container
    );
    delete instancesByReactRootID[reactRootID];
    delete containersByReactRootID[reactRootID];
    if (__DEV__) {
      delete rootElementsByReactRootID[reactRootID];
    }
    return true;
  },
示例#12
0
/**
 * True if the supplied DOM node has a direct React-rendered child that is
 * not a React root element. Useful for warning in `render`,
 * `unmountComponentAtNode`, etc.
 *
 * @param {?DOMElement} node The candidate DOM node.
 * @return {boolean} True if the DOM element contains a direct child that was
 * rendered by React but is not a root element.
 * @internal
 */
function hasNonRootReactChild(node) {
  var reactRootID = getReactRootID(node);
  return reactRootID ? reactRootID !==
    ReactInstanceHandles.getReactRootIDFromNodeID(reactRootID) : false;
}