Permalink
| /** | |
| * Copyright 2013-present, Facebook, Inc. | |
| * All rights reserved. | |
| * | |
| * This source code is licensed under the BSD-style license found in the | |
| * LICENSE file in the root directory of this source tree. An additional grant | |
| * of patent rights can be found in the PATENTS file in the same directory. | |
| * | |
| * @providesModule ReactMount | |
| */ | |
| 'use strict'; | |
| var DOMLazyTree = require('DOMLazyTree'); | |
| var DOMProperty = require('DOMProperty'); | |
| var React = require('React'); | |
| var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter'); | |
| var ReactCurrentOwner = require('ReactCurrentOwner'); | |
| var ReactDOMComponentTree = require('ReactDOMComponentTree'); | |
| var ReactDOMContainerInfo = require('ReactDOMContainerInfo'); | |
| var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags'); | |
| var ReactFeatureFlags = require('ReactFeatureFlags'); | |
| var ReactInstanceMap = require('ReactInstanceMap'); | |
| var ReactInstrumentation = require('ReactInstrumentation'); | |
| var ReactMarkupChecksum = require('ReactMarkupChecksum'); | |
| var ReactReconciler = require('ReactReconciler'); | |
| var ReactUpdateQueue = require('ReactUpdateQueue'); | |
| var ReactUpdates = require('ReactUpdates'); | |
| var emptyObject = require('emptyObject'); | |
| var instantiateReactComponent = require('instantiateReactComponent'); | |
| var invariant = require('invariant'); | |
| var setInnerHTML = require('setInnerHTML'); | |
| var shouldUpdateReactComponent = require('shouldUpdateReactComponent'); | |
| var warning = require('warning'); | |
| var ATTR_NAME = DOMProperty.ID_ATTRIBUTE_NAME; | |
| var ROOT_ATTR_NAME = DOMProperty.ROOT_ATTRIBUTE_NAME; | |
| var ELEMENT_NODE_TYPE = 1; | |
| var DOC_NODE_TYPE = 9; | |
| var DOCUMENT_FRAGMENT_NODE_TYPE = 11; | |
| var instancesByReactRootID = {}; | |
| /** | |
| * Finds the index of the first character | |
| * that's not common between the two given strings. | |
| * | |
| * @return {number} the index of the character where the strings diverge | |
| */ | |
| function firstDifferenceIndex(string1, string2) { | |
| var minLen = Math.min(string1.length, string2.length); | |
| for (var i = 0; i < minLen; i++) { | |
| if (string1.charAt(i) !== string2.charAt(i)) { | |
| return i; | |
| } | |
| } | |
| return string1.length === string2.length ? -1 : minLen; | |
| } | |
| /** | |
| * @param {DOMElement|DOMDocument} container DOM element that may contain | |
| * a React component | |
| * @return {?*} DOM element that may have the reactRoot ID, or null. | |
| */ | |
| function getReactRootElementInContainer(container) { | |
| if (!container) { | |
| return null; | |
| } | |
| if (container.nodeType === DOC_NODE_TYPE) { | |
| return container.documentElement; | |
| } else { | |
| return container.firstChild; | |
| } | |
| } | |
| function internalGetID(node) { | |
| // If node is something like a window, document, or text node, none of | |
| // which support attributes or a .getAttribute method, gracefully return | |
| // the empty string, as if the attribute were missing. | |
| return node.getAttribute && node.getAttribute(ATTR_NAME) || ''; | |
| } | |
| /** | |
| * Mounts this component and inserts it into the DOM. | |
| * | |
| * @param {ReactComponent} componentInstance The instance to mount. | |
| * @param {DOMElement} container DOM element to mount into. | |
| * @param {ReactReconcileTransaction} transaction | |
| * @param {boolean} shouldReuseMarkup If true, do not insert markup | |
| */ | |
| function mountComponentIntoNode( | |
| wrapperInstance, | |
| container, | |
| transaction, | |
| shouldReuseMarkup, | |
| context | |
| ) { | |
| var markerName; | |
| if (ReactFeatureFlags.logTopLevelRenders) { | |
| var wrappedElement = wrapperInstance._currentElement.props.child; | |
| var type = wrappedElement.type; | |
| markerName = 'React mount: ' + ( | |
| typeof type === 'string' ? type : | |
| type.displayName || type.name | |
| ); | |
| console.time(markerName); | |
| } | |
| var markup = ReactReconciler.mountComponent( | |
| wrapperInstance, | |
| transaction, | |
| null, | |
| ReactDOMContainerInfo(wrapperInstance, container), | |
| context, | |
| 0 /* parentDebugID */ | |
| ); | |
| if (markerName) { | |
| console.timeEnd(markerName); | |
| } | |
| wrapperInstance._renderedComponent._topLevelWrapper = wrapperInstance; | |
| ReactMount._mountImageIntoNode( | |
| markup, | |
| container, | |
| wrapperInstance, | |
| shouldReuseMarkup, | |
| transaction | |
| ); | |
| } | |
| /** | |
| * Batched mount. | |
| * | |
| * @param {ReactComponent} componentInstance The instance to mount. | |
| * @param {DOMElement} container DOM element to mount into. | |
| * @param {boolean} shouldReuseMarkup If true, do not insert markup | |
| */ | |
| function batchedMountComponentIntoNode( | |
| componentInstance, | |
| container, | |
| shouldReuseMarkup, | |
| context | |
| ) { | |
| var transaction = ReactUpdates.ReactReconcileTransaction.getPooled( | |
| /* useCreateElement */ | |
| !shouldReuseMarkup && ReactDOMFeatureFlags.useCreateElement | |
| ); | |
| transaction.perform( | |
| mountComponentIntoNode, | |
| null, | |
| componentInstance, | |
| container, | |
| transaction, | |
| shouldReuseMarkup, | |
| context | |
| ); | |
| ReactUpdates.ReactReconcileTransaction.release(transaction); | |
| } | |
| /** | |
| * Unmounts a component and removes it from the DOM. | |
| * | |
| * @param {ReactComponent} instance React component instance. | |
| * @param {DOMElement} container DOM element to unmount from. | |
| * @final | |
| * @internal | |
| * @see {ReactMount.unmountComponentAtNode} | |
| */ | |
| function unmountComponentFromNode(instance, container, safely) { | |
| if (__DEV__) { | |
| ReactInstrumentation.debugTool.onBeginFlush(); | |
| } | |
| ReactReconciler.unmountComponent(instance, safely); | |
| if (__DEV__) { | |
| ReactInstrumentation.debugTool.onEndFlush(); | |
| } | |
| if (container.nodeType === DOC_NODE_TYPE) { | |
| container = container.documentElement; | |
| } | |
| // http://jsperf.com/emptying-a-node | |
| while (container.lastChild) { | |
| container.removeChild(container.lastChild); | |
| } | |
| } | |
| /** | |
| * 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(container) { | |
| var rootEl = getReactRootElementInContainer(container); | |
| if (rootEl) { | |
| var inst = ReactDOMComponentTree.getInstanceFromNode(rootEl); | |
| return !!(inst && inst._hostParent); | |
| } | |
| } | |
| /** | |
| * True if the supplied DOM node is a React DOM element and | |
| * it has been rendered by another copy of React. | |
| * | |
| * @param {?DOMElement} node The candidate DOM node. | |
| * @return {boolean} True if the DOM has been rendered by another copy of React | |
| * @internal | |
| */ | |
| function nodeIsRenderedByOtherInstance(container) { | |
| var rootEl = getReactRootElementInContainer(container); | |
| return !!(rootEl && isReactNode(rootEl) && !ReactDOMComponentTree.getInstanceFromNode(rootEl)); | |
| } | |
| /** | |
| * True if the supplied DOM node is a valid node element. | |
| * | |
| * @param {?DOMElement} node The candidate DOM node. | |
| * @return {boolean} True if the DOM is a valid DOM node. | |
| * @internal | |
| */ | |
| function isValidContainer(node) { | |
| return !!(node && ( | |
| node.nodeType === ELEMENT_NODE_TYPE || | |
| node.nodeType === DOC_NODE_TYPE || | |
| node.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE | |
| )); | |
| } | |
| /** | |
| * True if the supplied DOM node is a valid React node element. | |
| * | |
| * @param {?DOMElement} node The candidate DOM node. | |
| * @return {boolean} True if the DOM is a valid React DOM node. | |
| * @internal | |
| */ | |
| function isReactNode(node) { | |
| return isValidContainer(node) && (node.hasAttribute(ROOT_ATTR_NAME) || node.hasAttribute(ATTR_NAME)); | |
| } | |
| function getHostRootInstanceInContainer(container) { | |
| var rootEl = getReactRootElementInContainer(container); | |
| var prevHostInstance = | |
| rootEl && ReactDOMComponentTree.getInstanceFromNode(rootEl); | |
| return ( | |
| prevHostInstance && !prevHostInstance._hostParent ? | |
| prevHostInstance : null | |
| ); | |
| } | |
| function getTopLevelWrapperInContainer(container) { | |
| var root = getHostRootInstanceInContainer(container); | |
| return root ? root._hostContainerInfo._topLevelWrapper : null; | |
| } | |
| /** | |
| * Temporary (?) hack so that we can store all top-level pending updates on | |
| * composites instead of having to worry about different types of components | |
| * here. | |
| */ | |
| var topLevelRootCounter = 1; | |
| var TopLevelWrapper = function() { | |
| this.rootID = topLevelRootCounter++; | |
| }; | |
| TopLevelWrapper.prototype.isReactComponent = {}; | |
| if (__DEV__) { | |
| TopLevelWrapper.displayName = 'TopLevelWrapper'; | |
| } | |
| TopLevelWrapper.prototype.render = function() { | |
| return this.props.child; | |
| }; | |
| TopLevelWrapper.isReactTopLevelWrapper = true; | |
| /** | |
| * Mounting is the process of initializing a React component by creating its | |
| * representative DOM elements and inserting them into a supplied `container`. | |
| * Any prior content inside `container` is destroyed in the process. | |
| * | |
| * ReactMount.render( | |
| * component, | |
| * document.getElementById('container') | |
| * ); | |
| * | |
| * <div id="container"> <-- Supplied `container`. | |
| * <div data-reactid=".3"> <-- Rendered reactRoot of React | |
| * // ... component. | |
| * </div> | |
| * </div> | |
| * | |
| * Inside of `container`, the first element rendered is the "reactRoot". | |
| */ | |
| var ReactMount = { | |
| TopLevelWrapper: TopLevelWrapper, | |
| /** | |
| * Used by devtools. The keys are not important. | |
| */ | |
| _instancesByReactRootID: instancesByReactRootID, | |
| /** | |
| * This is a hook provided to support rendering React components while | |
| * ensuring that the apparent scroll position of its `container` does not | |
| * change. | |
| * | |
| * @param {DOMElement} container The `container` being rendered into. | |
| * @param {function} renderCallback This must be called once to do the render. | |
| */ | |
| scrollMonitor: function(container, renderCallback) { | |
| renderCallback(); | |
| }, | |
| /** | |
| * Take a component that's already mounted into the DOM and replace its props | |
| * @param {ReactComponent} prevComponent component instance already in the DOM | |
| * @param {ReactElement} nextElement component instance to render | |
| * @param {DOMElement} container container to render into | |
| * @param {?function} callback function triggered on completion | |
| */ | |
| _updateRootComponent: function( | |
| prevComponent, | |
| nextElement, | |
| nextContext, | |
| container, | |
| callback) { | |
| ReactMount.scrollMonitor(container, function() { | |
| ReactUpdateQueue.enqueueElementInternal(prevComponent, nextElement, nextContext); | |
| if (callback) { | |
| ReactUpdateQueue.enqueueCallbackInternal(prevComponent, callback); | |
| } | |
| }); | |
| return prevComponent; | |
| }, | |
| /** | |
| * Render a new component into the DOM. Hooked by hooks! | |
| * | |
| * @param {ReactElement} nextElement element to render | |
| * @param {DOMElement} container container to render into | |
| * @param {boolean} shouldReuseMarkup if we should skip the markup insertion | |
| * @return {ReactComponent} nextComponent | |
| */ | |
| _renderNewRootComponent: function( | |
| nextElement, | |
| container, | |
| shouldReuseMarkup, | |
| context | |
| ) { | |
| // Various parts of our code (such as ReactCompositeComponent's | |
| // _renderValidatedComponent) assume that calls to render aren't nested; | |
| // verify that that's the case. | |
| warning( | |
| ReactCurrentOwner.current == null, | |
| '_renderNewRootComponent(): 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( | |
| isValidContainer(container), | |
| '_registerComponent(...): Target container is not a DOM element.' | |
| ); | |
| ReactBrowserEventEmitter.ensureScrollValueMonitoring(); | |
| var componentInstance = instantiateReactComponent(nextElement, false); | |
| // The initial render is synchronous but any updates that happen during | |
| // rendering, in componentWillMount or componentDidMount, will be batched | |
| // according to the current batching strategy. | |
| ReactUpdates.batchedUpdates( | |
| batchedMountComponentIntoNode, | |
| componentInstance, | |
| container, | |
| shouldReuseMarkup, | |
| context | |
| ); | |
| var wrapperID = componentInstance._instance.rootID; | |
| instancesByReactRootID[wrapperID] = componentInstance; | |
| return componentInstance; | |
| }, | |
| /** | |
| * Renders a React component into the DOM in the supplied `container`. | |
| * | |
| * If the React component was previously rendered into `container`, this will | |
| * perform an update on it and only mutate the DOM as necessary to reflect the | |
| * latest React component. | |
| * | |
| * @param {ReactComponent} parentComponent The conceptual parent of this render tree. | |
| * @param {ReactElement} nextElement Component element to render. | |
| * @param {DOMElement} container DOM element to render into. | |
| * @param {?function} callback function triggered on completion | |
| * @return {ReactComponent} Component instance rendered in `container`. | |
| */ | |
| renderSubtreeIntoContainer: function(parentComponent, nextElement, container, callback) { | |
| invariant( | |
| parentComponent != null && ReactInstanceMap.has(parentComponent), | |
| 'parentComponent must be a valid React Component' | |
| ); | |
| return ReactMount._renderSubtreeIntoContainer( | |
| parentComponent, | |
| nextElement, | |
| container, | |
| callback | |
| ); | |
| }, | |
| _renderSubtreeIntoContainer: function(parentComponent, nextElement, container, callback) { | |
| ReactUpdateQueue.validateCallback(callback, 'ReactDOM.render'); | |
| invariant( | |
| React.isValidElement(nextElement), | |
| 'ReactDOM.render(): Invalid component element.%s', | |
| ( | |
| typeof nextElement === 'string' ? | |
| ' Instead of passing a string like \'div\', pass ' + | |
| 'React.createElement(\'div\') or <div />.' : | |
| typeof nextElement === 'function' ? | |
| ' Instead of passing a class like Foo, pass ' + | |
| 'React.createElement(Foo) or <Foo />.' : | |
| // Check if it quacks like an element | |
| nextElement != null && nextElement.props !== undefined ? | |
| ' This may be caused by unintentionally loading two independent ' + | |
| 'copies of React.' : | |
| '' | |
| ) | |
| ); | |
| warning( | |
| !container || !container.tagName || | |
| container.tagName.toUpperCase() !== 'BODY', | |
| 'render(): Rendering components directly into document.body is ' + | |
| 'discouraged, since its children are often manipulated by third-party ' + | |
| 'scripts and browser extensions. This may lead to subtle ' + | |
| 'reconciliation issues. Try rendering into a container element created ' + | |
| 'for your app.' | |
| ); | |
| var nextWrappedElement = React.createElement( | |
| TopLevelWrapper, | |
| { child: nextElement } | |
| ); | |
| var nextContext; | |
| if (parentComponent) { | |
| var parentInst = ReactInstanceMap.get(parentComponent); | |
| nextContext = parentInst._processChildContext(parentInst._context); | |
| } else { | |
| nextContext = emptyObject; | |
| } | |
| var prevComponent = getTopLevelWrapperInContainer(container); | |
| if (prevComponent) { | |
| var prevWrappedElement = prevComponent._currentElement; | |
| var prevElement = prevWrappedElement.props.child; | |
| if (shouldUpdateReactComponent(prevElement, nextElement)) { | |
| var publicInst = prevComponent._renderedComponent.getPublicInstance(); | |
| var updatedCallback = callback && function() { | |
| callback.call(publicInst); | |
| }; | |
| ReactMount._updateRootComponent( | |
| prevComponent, | |
| nextWrappedElement, | |
| nextContext, | |
| container, | |
| updatedCallback | |
| ); | |
| return publicInst; | |
| } else { | |
| ReactMount.unmountComponentAtNode(container); | |
| } | |
| } | |
| var reactRootElement = getReactRootElementInContainer(container); | |
| var containerHasReactMarkup = | |
| reactRootElement && !!internalGetID(reactRootElement); | |
| var containerHasNonRootReactChild = hasNonRootReactChild(container); | |
| if (__DEV__) { | |
| warning( | |
| !containerHasNonRootReactChild, | |
| 'render(...): Replacing React-rendered children with a new root ' + | |
| 'component. If you intended to update the children of this node, ' + | |
| 'you should instead have the existing children update their state ' + | |
| 'and render the new components instead of calling ReactDOM.render.' | |
| ); | |
| if (!containerHasReactMarkup || reactRootElement.nextSibling) { | |
| var rootElementSibling = reactRootElement; | |
| while (rootElementSibling) { | |
| if (internalGetID(rootElementSibling)) { | |
| warning( | |
| false, | |
| 'render(): Target node has markup rendered by React, but there ' + | |
| 'are unrelated nodes as well. This is most commonly caused by ' + | |
| 'white-space inserted around server-rendered markup.' | |
| ); | |
| break; | |
| } | |
| rootElementSibling = rootElementSibling.nextSibling; | |
| } | |
| } | |
| } | |
| var shouldReuseMarkup = | |
| containerHasReactMarkup && | |
| !prevComponent && | |
| !containerHasNonRootReactChild; | |
| var component = ReactMount._renderNewRootComponent( | |
| nextWrappedElement, | |
| container, | |
| shouldReuseMarkup, | |
| nextContext | |
| )._renderedComponent.getPublicInstance(); | |
| if (callback) { | |
| callback.call(component); | |
| } | |
| return component; | |
| }, | |
| /** | |
| * Renders a React component into the DOM in the supplied `container`. | |
| * See https://facebook.github.io/react/docs/top-level-api.html#reactdom.render | |
| * | |
| * If the React component was previously rendered into `container`, this will | |
| * perform an update on it and only mutate the DOM as necessary to reflect the | |
| * latest React component. | |
| * | |
| * @param {ReactElement} nextElement Component element to render. | |
| * @param {DOMElement} container DOM element to render into. | |
| * @param {?function} callback function triggered on completion | |
| * @return {ReactComponent} Component instance rendered in `container`. | |
| */ | |
| render: function(nextElement, container, callback) { | |
| return ReactMount._renderSubtreeIntoContainer(null, nextElement, container, callback); | |
| }, | |
| /** | |
| * Unmounts and destroys the React component rendered in the `container`. | |
| * See https://facebook.github.io/react/docs/top-level-api.html#reactdom.unmountcomponentatnode | |
| * | |
| * @param {DOMElement} container DOM element containing a React component. | |
| * @return {boolean} True if a component was found in and unmounted from | |
| * `container` | |
| */ | |
| 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( | |
| isValidContainer(container), | |
| 'unmountComponentAtNode(...): Target container is not a DOM element.' | |
| ); | |
| if (__DEV__) { | |
| warning( | |
| !nodeIsRenderedByOtherInstance(container), | |
| 'unmountComponentAtNode(): The node you\'re attempting to unmount ' + | |
| 'was rendered by another copy of React.' | |
| ); | |
| } | |
| var prevComponent = getTopLevelWrapperInContainer(container); | |
| if (!prevComponent) { | |
| // 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 isContainerReactRoot = | |
| container.nodeType === 1 && container.hasAttribute(ROOT_ATTR_NAME); | |
| 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; | |
| } | |
| delete instancesByReactRootID[prevComponent._instance.rootID]; | |
| ReactUpdates.batchedUpdates( | |
| unmountComponentFromNode, | |
| prevComponent, | |
| container, | |
| false | |
| ); | |
| return true; | |
| }, | |
| _mountImageIntoNode: function( | |
| markup, | |
| container, | |
| instance, | |
| shouldReuseMarkup, | |
| transaction | |
| ) { | |
| invariant( | |
| isValidContainer(container), | |
| 'mountComponentIntoNode(...): Target container is not valid.' | |
| ); | |
| if (shouldReuseMarkup) { | |
| var rootElement = getReactRootElementInContainer(container); | |
| if (ReactMarkupChecksum.canReuseMarkup(markup, rootElement)) { | |
| ReactDOMComponentTree.precacheNode(instance, rootElement); | |
| return; | |
| } else { | |
| var checksum = rootElement.getAttribute( | |
| ReactMarkupChecksum.CHECKSUM_ATTR_NAME | |
| ); | |
| rootElement.removeAttribute(ReactMarkupChecksum.CHECKSUM_ATTR_NAME); | |
| var rootMarkup = rootElement.outerHTML; | |
| rootElement.setAttribute( | |
| ReactMarkupChecksum.CHECKSUM_ATTR_NAME, | |
| checksum | |
| ); | |
| var normalizedMarkup = markup; | |
| if (__DEV__) { | |
| // because rootMarkup is retrieved from the DOM, various normalizations | |
| // will have occurred which will not be present in `markup`. Here, | |
| // insert markup into a <div> or <iframe> depending on the container | |
| // type to perform the same normalizations before comparing. | |
| var normalizer; | |
| if (container.nodeType === ELEMENT_NODE_TYPE) { | |
| normalizer = document.createElement('div'); | |
| normalizer.innerHTML = markup; | |
| normalizedMarkup = normalizer.innerHTML; | |
| } else { | |
| normalizer = document.createElement('iframe'); | |
| document.body.appendChild(normalizer); | |
| normalizer.contentDocument.write(markup); | |
| normalizedMarkup = normalizer.contentDocument.documentElement.outerHTML; | |
| document.body.removeChild(normalizer); | |
| } | |
| } | |
| var diffIndex = firstDifferenceIndex(normalizedMarkup, rootMarkup); | |
| var difference = ' (client) ' + | |
| normalizedMarkup.substring(diffIndex - 20, diffIndex + 20) + | |
| '\n (server) ' + rootMarkup.substring(diffIndex - 20, diffIndex + 20); | |
| invariant( | |
| container.nodeType !== DOC_NODE_TYPE, | |
| 'You\'re trying to render a component to the document using ' + | |
| 'server rendering but the checksum was invalid. This usually ' + | |
| 'means you rendered a different component type or props on ' + | |
| 'the client from the one on the server, or your render() ' + | |
| 'methods are impure. React cannot handle this case due to ' + | |
| 'cross-browser quirks by rendering at the document root. You ' + | |
| 'should look for environment dependent code in your components ' + | |
| 'and ensure the props are the same client and server side:\n%s', | |
| difference | |
| ); | |
| if (__DEV__) { | |
| warning( | |
| false, | |
| 'React attempted to reuse markup in a container but the ' + | |
| 'checksum was invalid. This generally means that you are ' + | |
| 'using server rendering and the markup generated on the ' + | |
| 'server was not what the client was expecting. React injected ' + | |
| 'new markup to compensate which works but you have lost many ' + | |
| 'of the benefits of server rendering. Instead, figure out ' + | |
| 'why the markup being generated is different on the client ' + | |
| 'or server:\n%s', | |
| difference | |
| ); | |
| } | |
| } | |
| } | |
| invariant( | |
| container.nodeType !== DOC_NODE_TYPE, | |
| 'You\'re trying to render a component to the document but ' + | |
| 'you didn\'t use server rendering. We can\'t do this ' + | |
| 'without using server rendering due to cross-browser quirks. ' + | |
| 'See ReactDOMServer.renderToString() for server rendering.' | |
| ); | |
| if (transaction.useCreateElement) { | |
| while (container.lastChild) { | |
| container.removeChild(container.lastChild); | |
| } | |
| DOMLazyTree.insertTreeBefore(container, markup, null); | |
| } else { | |
| setInnerHTML(container, markup); | |
| ReactDOMComponentTree.precacheNode(instance, container.firstChild); | |
| } | |
| if (__DEV__) { | |
| var hostNode = ReactDOMComponentTree.getInstanceFromNode(container.firstChild); | |
| if (hostNode._debugID !== 0) { | |
| ReactInstrumentation.debugTool.onHostOperation({ | |
| instanceID: hostNode._debugID, | |
| type: 'mount', | |
| payload: markup.toString(), | |
| }); | |
| } | |
| } | |
| }, | |
| }; | |
| module.exports = ReactMount; |