updateComponent: function(transaction, prevElement, nextElement, context) { var lastProps = prevElement.props; var nextProps = this._currentElement.props; switch (this._tag) { case 'input': lastProps = ReactDOMInput.getHostProps(this, lastProps); nextProps = ReactDOMInput.getHostProps(this, nextProps); break; case 'option': lastProps = ReactDOMOption.getHostProps(this, lastProps); nextProps = ReactDOMOption.getHostProps(this, nextProps); break; case 'select': lastProps = ReactDOMSelect.getHostProps(this, lastProps); nextProps = ReactDOMSelect.getHostProps(this, nextProps); break; case 'textarea': lastProps = ReactDOMTextarea.getHostProps(this, lastProps); nextProps = ReactDOMTextarea.getHostProps(this, nextProps); break; default: if (typeof lastProps.onClick !== 'function' && typeof nextProps.onClick === 'function') { transaction.getReactMountReady().enqueue( trapClickOnNonInteractiveElement, this ); } break; } assertValidProps(this, nextProps); var isCustomComponentTag = isCustomComponent(this._tag, nextProps); this._updateDOMProperties(lastProps, nextProps, transaction, isCustomComponentTag); this._updateDOMChildren( lastProps, nextProps, transaction, context ); switch (this._tag) { case 'input': // Update the wrapper around inputs *after* updating props. This has to // happen after `_updateDOMProperties`. Otherwise HTML5 input validations // raise warnings and prevent the new value from being assigned. ReactDOMInput.updateWrapper(this); break; case 'textarea': ReactDOMTextarea.updateWrapper(this); break; case 'select': // <select> value update needs to occur after <option> children // reconciliation transaction.getReactMountReady().enqueue(postUpdateSelectWrapper, this); break; } },
updateComponent: function(transaction, prevElement, nextElement, context) { var lastProps = prevElement.props; var nextProps = this._currentElement.props; switch (this._tag) { case 'button': lastProps = ReactDOMButton.getHostProps(this, lastProps); nextProps = ReactDOMButton.getHostProps(this, nextProps); break; case 'input': ReactDOMInput.updateWrapper(this); lastProps = ReactDOMInput.getHostProps(this, lastProps); nextProps = ReactDOMInput.getHostProps(this, nextProps); break; case 'option': lastProps = ReactDOMOption.getHostProps(this, lastProps); nextProps = ReactDOMOption.getHostProps(this, nextProps); break; case 'select': lastProps = ReactDOMSelect.getHostProps(this, lastProps); nextProps = ReactDOMSelect.getHostProps(this, nextProps); break; case 'textarea': ReactDOMTextarea.updateWrapper(this); lastProps = ReactDOMTextarea.getHostProps(this, lastProps); nextProps = ReactDOMTextarea.getHostProps(this, nextProps); break; } assertValidProps(this, nextProps); this._updateDOMProperties(lastProps, nextProps, transaction); this._updateDOMChildren( lastProps, nextProps, transaction, context ); if (this._tag === 'select') { // <select> value update needs to occur after <option> children // reconciliation transaction.getReactMountReady().enqueue(postUpdateSelectWrapper, this); } },
mountComponent: function( transaction, hostParent, hostContainerInfo, context ) { this._rootNodeID = globalIdCounter++; this._domID = hostContainerInfo._idCounter++; this._hostParent = hostParent; this._hostContainerInfo = hostContainerInfo; var props = this._currentElement.props; switch (this._tag) { case 'iframe': case 'object': case 'img': case 'form': case 'video': case 'audio': this._wrapperState = { listeners: null, }; transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this); break; case 'button': props = ReactDOMButton.getHostProps(this, props, hostParent); break; case 'input': ReactDOMInput.mountWrapper(this, props, hostParent); props = ReactDOMInput.getHostProps(this, props); transaction.getReactMountReady().enqueue(trackInputValue, this); transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this); break; case 'option': ReactDOMOption.mountWrapper(this, props, hostParent); props = ReactDOMOption.getHostProps(this, props); break; case 'select': ReactDOMSelect.mountWrapper(this, props, hostParent); props = ReactDOMSelect.getHostProps(this, props); transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this); break; case 'textarea': ReactDOMTextarea.mountWrapper(this, props, hostParent); props = ReactDOMTextarea.getHostProps(this, props); transaction.getReactMountReady().enqueue(trackInputValue, this); transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this); break; } assertValidProps(this, props); // We create tags in the namespace of their parent container, except HTML // tags get no namespace. var namespaceURI; var parentTag; if (hostParent != null) { namespaceURI = hostParent._namespaceURI; parentTag = hostParent._tag; } else if (hostContainerInfo._tag) { namespaceURI = hostContainerInfo._namespaceURI; parentTag = hostContainerInfo._tag; } if (namespaceURI == null || namespaceURI === DOMNamespaces.svg && parentTag === 'foreignobject') { namespaceURI = DOMNamespaces.html; } if (namespaceURI === DOMNamespaces.html) { if (this._tag === 'svg') { namespaceURI = DOMNamespaces.svg; } else if (this._tag === 'math') { namespaceURI = DOMNamespaces.mathml; } } this._namespaceURI = namespaceURI; if (__DEV__) { var parentInfo; if (hostParent != null) { parentInfo = hostParent._ancestorInfo; } else if (hostContainerInfo._tag) { parentInfo = hostContainerInfo._ancestorInfo; } if (parentInfo) { // parentInfo should always be present except for the top-level // component when server rendering validateDOMNesting(this._tag, this, parentInfo); } this._ancestorInfo = validateDOMNesting.updatedAncestorInfo(parentInfo, this._tag, this); } var mountImage; if (transaction.useCreateElement) { var ownerDocument = hostContainerInfo._ownerDocument; var el; if (namespaceURI === DOMNamespaces.html) { if (this._tag === 'script') { // Create the script via .innerHTML so its "parser-inserted" flag is // set to true and it does not execute var div = ownerDocument.createElement('div'); var type = this._currentElement.type; div.innerHTML = `<${type}></${type}>`; el = div.removeChild(div.firstChild); } else { el = ownerDocument.createElement(this._currentElement.type, props.is || null); } } else { el = ownerDocument.createElementNS( namespaceURI, this._currentElement.type ); } ReactDOMComponentTree.precacheNode(this, el); this._flags |= Flags.hasCachedChildNodes; if (!this._hostParent) { DOMPropertyOperations.setAttributeForRoot(el); } this._updateDOMProperties(null, props, transaction); var lazyTree = DOMLazyTree(el); this._createInitialChildren(transaction, props, context, lazyTree); mountImage = lazyTree; } else { var tagOpen = this._createOpenTagMarkupAndPutListeners(transaction, props); var tagContent = this._createContentMarkup(transaction, props, context); if (!tagContent && omittedCloseTags[this._tag]) { mountImage = tagOpen + '/>'; } else { mountImage = tagOpen + '>' + tagContent + '</' + this._currentElement.type + '>'; } } switch (this._tag) { case 'input': case 'textarea': case 'select': case 'button': if (props.autoFocus) { transaction.getReactMountReady().enqueue( AutoFocusUtils.focusDOMComponent, this ); } break; case 'option': transaction.getReactMountReady().enqueue( optionPostMount, this ); } return mountImage; },
mountComponent: function( transaction, hostParent, hostContainerInfo, context, ) { this._rootNodeID = globalIdCounter++; this._domID = hostContainerInfo._idCounter++; this._hostParent = hostParent; this._hostContainerInfo = hostContainerInfo; var props = this._currentElement.props; switch (this._tag) { case 'audio': case 'form': case 'iframe': case 'img': case 'image': case 'link': case 'object': case 'source': case 'video': case 'details': this._wrapperState = { listeners: null, }; transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this); break; case 'input': ReactDOMInput.mountWrapper(this, props, hostParent); props = ReactDOMInput.getHostProps(this, props); transaction.getReactMountReady().enqueue(trackInputValue, this); transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this); // For controlled components we always need to ensure we're listening // to onChange. Even if there is no listener. ensureListeningTo(this, 'onChange', transaction); break; case 'option': ReactDOMOption.mountWrapper(this, props, hostParent); props = ReactDOMOption.getHostProps(this, props); break; case 'select': ReactDOMSelect.mountWrapper(this, props, hostParent); props = ReactDOMSelect.getHostProps(this, props); transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this); // For controlled components we always need to ensure we're listening // to onChange. Even if there is no listener. ensureListeningTo(this, 'onChange', transaction); break; case 'textarea': ReactDOMTextarea.mountWrapper(this, props, hostParent); props = ReactDOMTextarea.getHostProps(this, props); transaction.getReactMountReady().enqueue(trackInputValue, this); transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this); // For controlled components we always need to ensure we're listening // to onChange. Even if there is no listener. ensureListeningTo(this, 'onChange', transaction); break; } assertValidProps(this, props); // We create tags in the namespace of their parent container, except HTML // tags get no namespace. var namespaceURI; var parentTag; if (hostParent != null) { namespaceURI = hostParent._namespaceURI; parentTag = hostParent._tag; } else if (hostContainerInfo._tag) { namespaceURI = hostContainerInfo._namespaceURI; parentTag = hostContainerInfo._tag; } if ( namespaceURI == null || (namespaceURI === Namespaces.svg && parentTag === 'foreignobject') ) { namespaceURI = Namespaces.html; } if (__DEV__) { var isCustomComponentTag = isCustomComponent(this._tag, props); } if (namespaceURI === Namespaces.html) { if (__DEV__) { warning( isCustomComponentTag || this._tag === this._currentElement.type, '<%s /> is using uppercase HTML. Always use lowercase HTML tags ' + 'in React.', this._currentElement.type, ); } if (this._tag === 'svg') { namespaceURI = Namespaces.svg; } else if (this._tag === 'math') { namespaceURI = Namespaces.mathml; } } this._namespaceURI = namespaceURI; if (__DEV__) { var parentInfo; if (hostParent != null) { parentInfo = hostParent._ancestorInfo; } else if (hostContainerInfo._tag) { parentInfo = hostContainerInfo._ancestorInfo; } if (parentInfo) { // parentInfo should always be present except for the top-level // component when server rendering validateDOMNesting(this._tag, null, this, parentInfo); } this._ancestorInfo = validateDOMNesting.updatedAncestorInfo( parentInfo, this._tag, this, ); } var mountImage; var type = this._currentElement.type; if (transaction.useCreateElement) { var ownerDocument = hostContainerInfo._ownerDocument; var el; if (namespaceURI === Namespaces.html) { if (this._tag === 'script') { // Create the script via .innerHTML so its "parser-inserted" flag is // set to true and it does not execute var div = ownerDocument.createElement('div'); div.innerHTML = `<${type}></${type}>`; el = div.removeChild(div.firstChild); } else if (typeof props.is === 'string') { el = ownerDocument.createElement(type, {is: props.is}); } else { // Separate else branch instead of using `props.is || undefined` above because of a Firefox bug. // See discussion in https://github.com/facebook/react/pull/6896 // and discussion in https://bugzilla.mozilla.org/show_bug.cgi?id=1276240 el = ownerDocument.createElement(type); } } else { el = ownerDocument.createElementNS(namespaceURI, type); } if (__DEV__) { if (isCustomComponentTag && !didWarnShadyDOM && el.shadyRoot) { var owner = this._currentElement._owner; var name = (owner && owner.getName()) || 'A component'; warning( false, '%s is using shady DOM. Using shady DOM with React can ' + 'cause things to break subtly.', name, ); didWarnShadyDOM = true; } if (this._namespaceURI === Namespaces.html) { if ( !isCustomComponentTag && Object.prototype.toString.call(el) === '[object HTMLUnknownElement]' && !Object.prototype.hasOwnProperty.call(warnedUnknownTags, this._tag) ) { warnedUnknownTags[this._tag] = true; warning( false, 'The tag <%s> is unrecognized in this browser. ' + 'If you meant to render a React component, start its name with ' + 'an uppercase letter.', this._tag, ); } } } ReactDOMComponentTree.precacheNode(this, el); this._flags |= Flags.hasCachedChildNodes; if (!this._hostParent) { DOMPropertyOperations.setAttributeForRoot(el); } this._updateDOMProperties(null, props, transaction, isCustomComponentTag); var lazyTree = DOMLazyTree(el); this._createInitialChildren(transaction, props, context, lazyTree); mountImage = lazyTree; } else { validateDangerousTag(this._tag); var tagOpen = this._createOpenTagMarkupAndPutListeners( transaction, props, ); var tagContent = this._createContentMarkup(transaction, props, context); if (!tagContent && omittedCloseTags[this._tag]) { mountImage = tagOpen + '/>'; } else { mountImage = tagOpen + '>' + tagContent + '</' + type + '>'; } } switch (this._tag) { case 'input': transaction.getReactMountReady().enqueue(inputPostMount, this); if (props.autoFocus) { transaction .getReactMountReady() .enqueue(AutoFocusUtils.focusDOMComponent, this); } break; case 'textarea': transaction.getReactMountReady().enqueue(textareaPostMount, this); if (props.autoFocus) { transaction .getReactMountReady() .enqueue(AutoFocusUtils.focusDOMComponent, this); } break; case 'select': if (props.autoFocus) { transaction .getReactMountReady() .enqueue(AutoFocusUtils.focusDOMComponent, this); } break; case 'button': if (props.autoFocus) { transaction .getReactMountReady() .enqueue(AutoFocusUtils.focusDOMComponent, this); } break; case 'option': transaction.getReactMountReady().enqueue(optionPostMount, this); break; default: if (typeof props.onClick === 'function') { transaction .getReactMountReady() .enqueue(trapClickOnNonInteractiveElement, this); } break; } return mountImage; },