@samitouri / QOS-React / commits / ec178acf15

Turn ReactDOMFiberComponent into a singleton

And turn on Flow.

Sebastian Markbage committed Nov 15, 2016 at 17:15 UTC ec178acf151f2642897f3ef5aa29005e059be4b8
5 files changed +472 -518
src/renderers/dom/fiber/ReactDOMFiberComponent.js
+468 -518
@@ -7,6 +7,7 @@
7 * of patent rights can be found in the PATENTS file in the same directory.
8 *
9 * @providesModule ReactDOMFiberComponent
10 + * @flow
11 */
12
13 /* global hasOwnProperty:true */
@@ -24,10 +25,10 @@ var EventPluginRegistry = require('EventPluginRegistry');
25 var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
26 var ReactDOMComponentFlags = require('ReactDOMComponentFlags');
27 var ReactDOMComponentTree = require('ReactDOMComponentTree');
27 -var ReactDOMInput = require('ReactDOMInput');
28 -var ReactDOMOption = require('ReactDOMOption');
29 -var ReactDOMSelect = require('ReactDOMSelect');
30 -var ReactDOMTextarea = require('ReactDOMTextarea');
28 +var ReactDOMFiberInput = require('ReactDOMFiberInput');
29 +var ReactDOMFiberOption = require('ReactDOMFiberOption');
30 +var ReactDOMFiberSelect = require('ReactDOMFiberSelect');
31 +var ReactDOMFiberTextarea = require('ReactDOMFiberTextarea');
32 var ReactInstrumentation = require('ReactInstrumentation');
33 var ReactMultiChild = require('ReactMultiChild');
34 var ReactServerRenderingTransaction = require('ReactServerRenderingTransaction');
@@ -258,17 +259,17 @@ function putListener() {
259
260 function inputPostMount() {
261 var inst = this;
261 - ReactDOMInput.postMountWrapper(inst);
262 + ReactDOMFiberInput.postMountWrapper(inst);
263 }
264
265 function textareaPostMount() {
266 var inst = this;
266 - ReactDOMTextarea.postMountWrapper(inst);
267 + ReactDOMFiberTextarea.postMountWrapper(inst);
268 }
269
270 function optionPostMount() {
271 var inst = this;
271 - ReactDOMOption.postMountWrapper(inst);
272 + ReactDOMFiberOption.postMountWrapper(inst);
273 }
274
275 var setAndValidateContentChildDev = emptyFunction;
@@ -437,7 +438,7 @@ function trapBubbledEventsLocal() {
438 }
439
440 function postUpdateSelectWrapper() {
440 - ReactDOMSelect.postUpdateWrapper(this);
441 + ReactDOMFiberSelect.postUpdateWrapper(this);
442 }
443
444 // For HTML, certain tags should omit their close tag. We keep a whitelist for
@@ -494,48 +495,372 @@ function isCustomComponent(tagName, props) {
495 return tagName.indexOf('-') >= 0 || props.is != null;
496 }
497
497 -var globalIdCounter = 1;
498
499 /**
500 - * Creates a new React class that is idempotent and capable of containing other
501 - * React components. It accepts event listeners and DOM properties that are
502 - * valid according to `DOMProperty`.
500 + * Creates markup for the open tag and all attributes.
501 *
504 - * - Event listeners: `onClick`, `onMouseDown`, etc.
505 - * - DOM properties: `className`, `name`, `title`, etc.
502 + * This method has side effects because events get registered.
503 *
507 - * The `style` property functions differently from the DOM API. It accepts an
508 - * object mapping of style properties to values.
504 + * Iterating over object properties is faster than iterating over arrays.
505 + * @see http://jsperf.com/obj-vs-arr-iteration
506 *
510 - * @constructor ReactDOMComponent
511 - * @extends ReactMultiChild
507 + * @private
508 + * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
509 + * @param {object} props
510 + * @return {string} Markup of opening tag.
511 */
513 -function ReactDOMComponent(element) {
514 - var tag = element.type;
515 - validateDangerousTag(tag);
516 - this._currentElement = element;
517 - this._tag = tag.toLowerCase();
518 - this._namespaceURI = null;
519 - this._renderedChildren = null;
520 - this._previousStyle = null;
521 - this._previousStyleCopy = null;
522 - this._hostNode = null;
523 - this._hostParent = null;
524 - this._rootNodeID = 0;
525 - this._domID = 0;
526 - this._hostContainerInfo = null;
527 - this._wrapperState = null;
528 - this._topLevelWrapper = null;
529 - this._flags = 0;
530 - if (__DEV__) {
531 - this._ancestorInfo = null;
532 - setAndValidateContentChildDev.call(this, null);
512 +function createOpenTagMarkupAndPutListeners(workInProgress, transaction, props) {
513 + var ret = '<' + workInProgress._currentElement.type;
514 +
515 + for (var propKey in props) {
516 + if (!props.hasOwnProperty(propKey)) {
517 + continue;
518 + }
519 + var propValue = props[propKey];
520 + if (propValue == null) {
521 + continue;
522 + }
523 + if (registrationNameModules.hasOwnProperty(propKey)) {
524 + if (propValue) {
525 + enqueuePutListener(workInProgress, propKey, propValue, transaction);
526 + }
527 + } else {
528 + if (propKey === STYLE) {
529 + if (propValue) {
530 + if (__DEV__) {
531 + // See `_updateDOMProperties`. style block
532 + workInProgress._previousStyle = propValue;
533 + }
534 + propValue = workInProgress._previousStyleCopy = Object.assign({}, props.style);
535 + }
536 + propValue = CSSPropertyOperations.createMarkupForStyles(propValue, workInProgress);
537 + }
538 + var markup = null;
539 + if (workInProgress._tag != null && isCustomComponent(workInProgress._tag, props)) {
540 + if (!RESERVED_PROPS.hasOwnProperty(propKey)) {
541 + markup = DOMPropertyOperations.createMarkupForCustomAttribute(propKey, propValue);
542 + }
543 + } else {
544 + markup = DOMPropertyOperations.createMarkupForProperty(propKey, propValue);
545 + }
546 + if (markup) {
547 + ret += ' ' + markup;
548 + }
549 + }
550 + }
551 +
552 + // For static pages, no need to put React ID and checksum. Saves lots of
553 + // bytes.
554 + if (transaction.renderToStaticMarkup) {
555 + return ret;
556 + }
557 +
558 + if (!workInProgress._hostParent) {
559 + ret += ' ' + DOMPropertyOperations.createMarkupForRoot();
560 + }
561 + ret += ' ' + DOMPropertyOperations.createMarkupForID(workInProgress._domID);
562 + return ret;
563 +}
564 +
565 +/**
566 + * Creates markup for the content between the tags.
567 + *
568 + * @private
569 + * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
570 + * @param {object} props
571 + * @param {object} context
572 + * @return {string} Content markup.
573 + */
574 +function createContentMarkup(workInProgress, transaction, props, context) {
575 + var ret = '';
576 +
577 + // Intentional use of != to avoid catching zero/false.
578 + var innerHTML = props.dangerouslySetInnerHTML;
579 + if (innerHTML != null) {
580 + if (innerHTML.__html != null) {
581 + ret = innerHTML.__html;
582 + }
583 + } else {
584 + var contentToUse =
585 + CONTENT_TYPES[typeof props.children] ? props.children : null;
586 + var childrenToUse = contentToUse != null ? null : props.children;
587 + if (contentToUse != null) {
588 + // TODO: Validate that text is allowed as a child of this node
589 + ret = escapeTextContentForBrowser(contentToUse);
590 + if (__DEV__) {
591 + setAndValidateContentChildDev.call(workInProgress, contentToUse);
592 + }
593 + } else if (childrenToUse != null) {
594 + var mountImages = workInProgress.mountChildren(
595 + childrenToUse,
596 + transaction,
597 + context
598 + );
599 + ret = mountImages.join('');
600 + }
601 + }
602 + if (newlineEatingTags[workInProgress._tag] && ret.charAt(0) === '\n') {
603 + // text/html ignores the first character in these tags if it's a newline
604 + // Prefer to break application/xml over text/html (for now) by adding
605 + // a newline specifically to get eaten by the parser. (Alternately for
606 + // textareas, replacing "^\n" with "\r\n" doesn't get eaten, and the first
607 + // \r is normalized out by HTMLTextAreaElement#value.)
608 + // See: <http://www.w3.org/TR/html-polyglot/#newlines-in-textarea-and-pre>
609 + // See: <http://www.w3.org/TR/html5/syntax.html#element-restrictions>
610 + // See: <http://www.w3.org/TR/html5/syntax.html#newlines>
611 + // See: Parsing of "textarea" "listing" and "pre" elements
612 + // from <http://www.w3.org/TR/html5/syntax.html#parsing-main-inbody>
613 + return '\n' + ret;
614 + } else {
615 + return ret;
616 + }
617 +}
618 +
619 +function createInitialChildren(workInProgress, transaction, props, context, lazyTree) {
620 + // Intentional use of != to avoid catching zero/false.
621 + var innerHTML = props.dangerouslySetInnerHTML;
622 + if (innerHTML != null) {
623 + if (innerHTML.__html != null) {
624 + DOMLazyTree.queueHTML(lazyTree, innerHTML.__html);
625 + }
626 + } else {
627 + var contentToUse =
628 + CONTENT_TYPES[typeof props.children] ? props.children : null;
629 + var childrenToUse = contentToUse != null ? null : props.children;
630 + // TODO: Validate that text is allowed as a child of this node
631 + if (contentToUse != null) {
632 + // Avoid setting textContent when the text is empty. In IE11 setting
633 + // textContent on a text area will cause the placeholder to not
634 + // show within the textarea until it has been focused and blurred again.
635 + // https://github.com/facebook/react/issues/6731#issuecomment-254874553
636 + if (contentToUse !== '') {
637 + if (__DEV__) {
638 + setAndValidateContentChildDev.call(workInProgress, contentToUse);
639 + }
640 + DOMLazyTree.queueText(lazyTree, contentToUse);
641 + }
642 + } else if (childrenToUse != null) {
643 + var mountImages = workInProgress.mountChildren(
644 + childrenToUse,
645 + transaction,
646 + context
647 + );
648 + for (var i = 0; i < mountImages.length; i++) {
649 + DOMLazyTree.queueChild(lazyTree, mountImages[i]);
650 + }
651 + }
652 + }
653 +}
654 +
655 +/**
656 + * Reconciles the properties by detecting differences in property values and
657 + * updating the DOM as necessary. This function is probably the single most
658 + * critical path for performance optimization.
659 + *
660 + * TODO: Benchmark whether checking for changed values in memory actually
661 + * improves performance (especially statically positioned elements).
662 + * TODO: Benchmark the effects of putting workInProgress at the top since 99% of props
663 + * do not change for a given reconciliation.
664 + * TODO: Benchmark areas that can be improved with caching.
665 + *
666 + * @private
667 + * @param {object} lastProps
668 + * @param {object} nextProps
669 + * @param {?DOMElement} node
670 + */
671 +function updateDOMProperties(
672 + workInProgress,
673 + lastProps,
674 + nextProps,
675 + transaction,
676 + isCustomComponentTag
677 +) {
678 + var propKey;
679 + var styleName;
680 + var styleUpdates;
681 + for (propKey in lastProps) {
682 + if (nextProps.hasOwnProperty(propKey) ||
683 + !lastProps.hasOwnProperty(propKey) ||
684 + lastProps[propKey] == null) {
685 + continue;
686 + }
687 + if (propKey === STYLE) {
688 + var lastStyle = workInProgress._previousStyleCopy;
689 + for (styleName in lastStyle) {
690 + if (lastStyle.hasOwnProperty(styleName)) {
691 + styleUpdates = styleUpdates || {};
692 + styleUpdates[styleName] = '';
693 + }
694 + }
695 + workInProgress._previousStyleCopy = null;
696 + } else if (registrationNameModules.hasOwnProperty(propKey)) {
697 + if (lastProps[propKey]) {
698 + // Only call deleteListener if there was a listener previously or
699 + // else willDeleteListener gets called when there wasn't actually a
700 + // listener (e.g., onClick={null})
701 + deleteListener(workInProgress, propKey);
702 + }
703 + } else if (isCustomComponent(workInProgress._tag, lastProps)) {
704 + if (!RESERVED_PROPS.hasOwnProperty(propKey)) {
705 + DOMPropertyOperations.deleteValueForAttribute(
706 + getNode(workInProgress),
707 + propKey
708 + );
709 + }
710 + } else if (
711 + DOMProperty.properties[propKey] ||
712 + DOMProperty.isCustomAttribute(propKey)) {
713 + DOMPropertyOperations.deleteValueForProperty(getNode(workInProgress), propKey);
714 + }
715 + }
716 + for (propKey in nextProps) {
717 + var nextProp = nextProps[propKey];
718 + var lastProp =
719 + propKey === STYLE ? workInProgress._previousStyleCopy :
720 + lastProps != null ? lastProps[propKey] : undefined;
721 + if (!nextProps.hasOwnProperty(propKey) ||
722 + nextProp === lastProp ||
723 + nextProp == null && lastProp == null) {
724 + continue;
725 + }
726 + if (propKey === STYLE) {
727 + if (nextProp) {
728 + if (__DEV__) {
729 + checkAndWarnForMutatedStyle(
730 + workInProgress._previousStyleCopy,
731 + workInProgress._previousStyle,
732 + workInProgress
733 + );
734 + workInProgress._previousStyle = nextProp;
735 + }
736 + nextProp = workInProgress._previousStyleCopy = Object.assign({}, nextProp);
737 + } else {
738 + workInProgress._previousStyleCopy = null;
739 + }
740 + if (lastProp) {
741 + // Unset styles on `lastProp` but not on `nextProp`.
742 + for (styleName in lastProp) {
743 + if (lastProp.hasOwnProperty(styleName) &&
744 + (!nextProp || !nextProp.hasOwnProperty(styleName))) {
745 + styleUpdates = styleUpdates || {};
746 + styleUpdates[styleName] = '';
747 + }
748 + }
749 + // Update styles that changed since `lastProp`.
750 + for (styleName in nextProp) {
751 + if (nextProp.hasOwnProperty(styleName) &&
752 + lastProp[styleName] !== nextProp[styleName]) {
753 + styleUpdates = styleUpdates || {};
754 + styleUpdates[styleName] = nextProp[styleName];
755 + }
756 + }
757 + } else {
758 + // Relies on `updateStylesByID` not mutating `styleUpdates`.
759 + styleUpdates = nextProp;
760 + }
761 + } else if (registrationNameModules.hasOwnProperty(propKey)) {
762 + if (nextProp) {
763 + enqueuePutListener(workInProgress, propKey, nextProp, transaction);
764 + } else if (lastProp) {
765 + deleteListener(workInProgress, propKey);
766 + }
767 + } else if (isCustomComponentTag) {
768 + if (!RESERVED_PROPS.hasOwnProperty(propKey)) {
769 + DOMPropertyOperations.setValueForAttribute(
770 + getNode(workInProgress),
771 + propKey,
772 + nextProp
773 + );
774 + }
775 + } else if (
776 + DOMProperty.properties[propKey] ||
777 + DOMProperty.isCustomAttribute(propKey)) {
778 + var node = getNode(workInProgress);
779 + // If we're updating to null or undefined, we should remove the property
780 + // from the DOM node instead of inadvertently setting to a string. This
781 + // brings us in line with the same behavior we have on initial render.
782 + if (nextProp != null) {
783 + DOMPropertyOperations.setValueForProperty(node, propKey, nextProp);
784 + } else {
785 + DOMPropertyOperations.deleteValueForProperty(node, propKey);
786 + }
787 + }
788 + }
789 + if (styleUpdates) {
790 + CSSPropertyOperations.setValueForStyles(
791 + getNode(workInProgress),
792 + styleUpdates,
793 + workInProgress
794 + );
795 + }
796 +}
797 +
798 +/**
799 + * Reconciles the children with the various properties that affect the
800 + * children content.
801 + *
802 + * @param {object} lastProps
803 + * @param {object} nextProps
804 + * @param {ReactReconcileTransaction} transaction
805 + * @param {object} context
806 + */
807 +function updateDOMChildren(workInProgress, lastProps, nextProps, transaction, context) {
808 + var lastContent =
809 + CONTENT_TYPES[typeof lastProps.children] ? lastProps.children : null;
810 + var nextContent =
811 + CONTENT_TYPES[typeof nextProps.children] ? nextProps.children : null;
812 +
813 + var lastHtml =
814 + lastProps.dangerouslySetInnerHTML &&
815 + lastProps.dangerouslySetInnerHTML.__html;
816 + var nextHtml =
817 + nextProps.dangerouslySetInnerHTML &&
818 + nextProps.dangerouslySetInnerHTML.__html;
819 +
820 + // Note the use of `!=` which checks for null or undefined.
821 + var lastChildren = lastContent != null ? null : lastProps.children;
822 + var nextChildren = nextContent != null ? null : nextProps.children;
823 +
824 + // If we're switching from children to content/html or vice versa, remove
825 + // the old content
826 + var lastHasContentOrHtml = lastContent != null || lastHtml != null;
827 + var nextHasContentOrHtml = nextContent != null || nextHtml != null;
828 + if (lastChildren != null && nextChildren == null) {
829 + workInProgress.updateChildren(null, transaction, context);
830 + } else if (lastHasContentOrHtml && !nextHasContentOrHtml) {
831 + workInProgress.updateTextContent('');
832 + if (__DEV__) {
833 + ReactInstrumentation.debugTool.onSetChildren(workInProgress._debugID, []);
834 + }
835 + }
836 +
837 + if (nextContent != null) {
838 + if (lastContent !== nextContent) {
839 + workInProgress.updateTextContent('' + nextContent);
840 + if (__DEV__) {
841 + setAndValidateContentChildDev.call(workInProgress, nextContent);
842 + }
843 + }
844 + } else if (nextHtml != null) {
845 + if (lastHtml !== nextHtml) {
846 + workInProgress.updateMarkup('' + nextHtml);
847 + }
848 + if (__DEV__) {
849 + ReactInstrumentation.debugTool.onSetChildren(workInProgress._debugID, []);
850 + }
851 + } else if (nextChildren != null) {
852 + if (__DEV__) {
853 + setAndValidateContentChildDev.call(workInProgress, null);
854 + }
855 +
856 + workInProgress.updateChildren(nextChildren, transaction, context);
857 }
858 }
859
536 -ReactDOMComponent.displayName = 'ReactDOMComponent';
860 +var globalIdCounter = 1;
861 +
862 +var ReactDOMFiberComponent = {
863
538 -ReactDOMComponent.Mixin = {
864
865 /**
866 * Generates root tag markup then recurses. This method has side effects and
@@ -549,19 +874,24 @@ ReactDOMComponent.Mixin = {
874 * @return {string} The computed markup.
875 */
876 mountComponent: function(
877 + workInProgress : Fiber,
878 transaction,
879 hostParent,
880 hostContainerInfo,
881 context
882 ) {
557 - this._rootNodeID = globalIdCounter++;
558 - this._domID = hostContainerInfo._idCounter++;
559 - this._hostParent = hostParent;
560 - this._hostContainerInfo = hostContainerInfo;
883 + // validateDangerousTag(tag);
884 + // workInProgress._tag = tag.toLowerCase();
885 + // setAndValidateContentChildDev.call(workInProgress, null);
886 +
887 + workInProgress._rootNodeID = globalIdCounter++;
888 + workInProgress._domID = hostContainerInfo._idCounter++;
889 + workInProgress._hostParent = hostParent;
890 + workInProgress._hostContainerInfo = hostContainerInfo;
891
562 - var props = this._currentElement.props;
892 + var props = workInProgress._currentElement.props;
893
564 - switch (this._tag) {
894 + switch (workInProgress._tag) {
895 case 'audio':
896 case 'form':
897 case 'iframe':
@@ -570,44 +900,44 @@ ReactDOMComponent.Mixin = {
900 case 'object':
901 case 'source':
902 case 'video':
573 - this._wrapperState = {
903 + workInProgress._wrapperState = {
904 listeners: null,
905 };
576 - transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this);
906 + transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, workInProgress);
907 break;
908 case 'input':
579 - ReactDOMInput.mountWrapper(this, props, hostParent);
580 - props = ReactDOMInput.getHostProps(this, props);
581 - transaction.getReactMountReady().enqueue(trackInputValue, this);
582 - transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this);
909 + ReactDOMFiberInput.mountWrapper(workInProgress, props, hostParent);
910 + props = ReactDOMFiberInput.getHostProps(workInProgress, props);
911 + transaction.getReactMountReady().enqueue(trackInputValue, workInProgress);
912 + transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, workInProgress);
913 // For controlled components we always need to ensure we're listening
914 // to onChange. Even if there is no listener.
585 - ensureListeningTo(this, 'onChange', transaction);
915 + ensureListeningTo(workInProgress, 'onChange', transaction);
916 break;
917 case 'option':
588 - ReactDOMOption.mountWrapper(this, props, hostParent);
589 - props = ReactDOMOption.getHostProps(this, props);
918 + ReactDOMFiberOption.mountWrapper(workInProgress, props, hostParent);
919 + props = ReactDOMFiberOption.getHostProps(workInProgress, props);
920 break;
921 case 'select':
592 - ReactDOMSelect.mountWrapper(this, props, hostParent);
593 - props = ReactDOMSelect.getHostProps(this, props);
594 - transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this);
922 + ReactDOMFiberSelect.mountWrapper(workInProgress, props, hostParent);
923 + props = ReactDOMFiberSelect.getHostProps(workInProgress, props);
924 + transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, workInProgress);
925 // For controlled components we always need to ensure we're listening
926 // to onChange. Even if there is no listener.
597 - ensureListeningTo(this, 'onChange', transaction);
927 + ensureListeningTo(workInProgress, 'onChange', transaction);
928 break;
929 case 'textarea':
600 - ReactDOMTextarea.mountWrapper(this, props, hostParent);
601 - props = ReactDOMTextarea.getHostProps(this, props);
602 - transaction.getReactMountReady().enqueue(trackInputValue, this);
603 - transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, this);
930 + ReactDOMFiberTextarea.mountWrapper(workInProgress, props, hostParent);
931 + props = ReactDOMFiberTextarea.getHostProps(workInProgress, props);
932 + transaction.getReactMountReady().enqueue(trackInputValue, workInProgress);
933 + transaction.getReactMountReady().enqueue(trapBubbledEventsLocal, workInProgress);
934 // For controlled components we always need to ensure we're listening
935 // to onChange. Even if there is no listener.
606 - ensureListeningTo(this, 'onChange', transaction);
936 + ensureListeningTo(workInProgress, 'onChange', transaction);
937 break;
938 }
939
610 - assertValidProps(this, props);
940 + assertValidProps(workInProgress, props);
941
942 // We create tags in the namespace of their parent container, except HTML
943 // tags get no namespace.
@@ -625,13 +955,13 @@ ReactDOMComponent.Mixin = {
955 namespaceURI = DOMNamespaces.html;
956 }
957 if (namespaceURI === DOMNamespaces.html) {
628 - if (this._tag === 'svg') {
958 + if (workInProgress._tag === 'svg') {
959 namespaceURI = DOMNamespaces.svg;
630 - } else if (this._tag === 'math') {
960 + } else if (workInProgress._tag === 'math') {
961 namespaceURI = DOMNamespaces.mathml;
962 }
963 }
634 - this._namespaceURI = namespaceURI;
964 + workInProgress._namespaceURI = namespaceURI;
965
966 if (__DEV__) {
967 var parentInfo;
@@ -643,19 +973,19 @@ ReactDOMComponent.Mixin = {
973 if (parentInfo) {
974 // parentInfo should always be present except for the top-level
975 // component when server rendering
646 - validateDOMNesting(this._tag, null, this, parentInfo);
976 + validateDOMNesting(workInProgress._tag, null, workInProgress, parentInfo);
977 }
648 - this._ancestorInfo =
649 - validateDOMNesting.updatedAncestorInfo(parentInfo, this._tag, this);
978 + workInProgress._ancestorInfo =
979 + validateDOMNesting.updatedAncestorInfo(parentInfo, workInProgress._tag, workInProgress);
980 }
981
982 var mountImage;
653 - var type = this._currentElement.type;
983 + var type = workInProgress._currentElement.type;
984 if (transaction.useCreateElement) {
985 var ownerDocument = hostContainerInfo._ownerDocument;
986 var el;
987 if (namespaceURI === DOMNamespaces.html) {
658 - if (this._tag === 'script') {
988 + if (workInProgress._tag === 'script') {
989 // Create the script via .innerHTML so its "parser-inserted" flag is
990 // set to true and it does not execute
991 var div = ownerDocument.createElement('div');
@@ -675,9 +1005,9 @@ ReactDOMComponent.Mixin = {
1005 type
1006 );
1007 }
678 - var isCustomComponentTag = isCustomComponent(this._tag, props);
1008 + var isCustomComponentTag = isCustomComponent(workInProgress._tag, props);
1009 if (__DEV__ && isCustomComponentTag && !didWarnShadyDOM && el.shadyRoot) {
680 - var owner = this._currentElement._owner;
1010 + var owner = workInProgress._currentElement._owner;
1011 var name = owner && owner.getName() || 'A component';
1012 warning(
1013 false,
@@ -687,47 +1017,47 @@ ReactDOMComponent.Mixin = {
1017 );
1018 didWarnShadyDOM = true;
1019 }
690 - ReactDOMComponentTree.precacheNode(this, el);
691 - this._flags |= Flags.hasCachedChildNodes;
692 - if (!this._hostParent) {
1020 + ReactDOMComponentTree.precacheNode(workInProgress, el);
1021 + workInProgress._flags |= Flags.hasCachedChildNodes;
1022 + if (!workInProgress._hostParent) {
1023 DOMPropertyOperations.setAttributeForRoot(el);
1024 }
695 - this._updateDOMProperties(null, props, transaction, isCustomComponentTag);
1025 + updateDOMProperties(workInProgress, null, props, transaction, isCustomComponentTag);
1026 var lazyTree = DOMLazyTree(el);
697 - this._createInitialChildren(transaction, props, context, lazyTree);
1027 + createInitialChildren(workInProgress, transaction, props, context, lazyTree);
1028 mountImage = lazyTree;
1029 } else {
700 - var tagOpen = this._createOpenTagMarkupAndPutListeners(transaction, props);
701 - var tagContent = this._createContentMarkup(transaction, props, context);
702 - if (!tagContent && omittedCloseTags[this._tag]) {
1030 + var tagOpen = createOpenTagMarkupAndPutListeners(workInProgress, transaction, props);
1031 + var tagContent = createContentMarkup(workInProgress, transaction, props, context);
1032 + if (!tagContent && omittedCloseTags[workInProgress._tag]) {
1033 mountImage = tagOpen + '/>';
1034 } else {
1035 mountImage = tagOpen + '>' + tagContent + '</' + type + '>';
1036 }
1037 }
1038
709 - switch (this._tag) {
1039 + switch (workInProgress._tag) {
1040 case 'input':
1041 transaction.getReactMountReady().enqueue(
1042 inputPostMount,
713 - this
1043 + workInProgress
1044 );
1045 if (props.autoFocus) {
1046 transaction.getReactMountReady().enqueue(
1047 AutoFocusUtils.focusDOMComponent,
718 - this
1048 + workInProgress
1049 );
1050 }
1051 break;
1052 case 'textarea':
1053 transaction.getReactMountReady().enqueue(
1054 textareaPostMount,
725 - this
1055 + workInProgress
1056 );
1057 if (props.autoFocus) {
1058 transaction.getReactMountReady().enqueue(
1059 AutoFocusUtils.focusDOMComponent,
730 - this
1060 + workInProgress
1061 );
1062 }
1063 break;
@@ -735,7 +1065,7 @@ ReactDOMComponent.Mixin = {
1065 if (props.autoFocus) {
1066 transaction.getReactMountReady().enqueue(
1067 AutoFocusUtils.focusDOMComponent,
738 - this
1068 + workInProgress
1069 );
1070 }
1071 break;
@@ -743,21 +1073,21 @@ ReactDOMComponent.Mixin = {
1073 if (props.autoFocus) {
1074 transaction.getReactMountReady().enqueue(
1075 AutoFocusUtils.focusDOMComponent,
746 - this
1076 + workInProgress
1077 );
1078 }
1079 break;
1080 case 'option':
1081 transaction.getReactMountReady().enqueue(
1082 optionPostMount,
753 - this
1083 + workInProgress
1084 );
1085 break;
1086 default:
1087 if (typeof props.onClick === 'function') {
1088 transaction.getReactMountReady().enqueue(
1089 trapClickOnNonInteractiveElement,
760 - this
1090 + workInProgress
1091 );
1092 }
1093 break;
@@ -766,161 +1096,6 @@ ReactDOMComponent.Mixin = {
1096 return mountImage;
1097 },
1098
769 - /**
770 - * Creates markup for the open tag and all attributes.
771 - *
772 - * This method has side effects because events get registered.
773 - *
774 - * Iterating over object properties is faster than iterating over arrays.
775 - * @see http://jsperf.com/obj-vs-arr-iteration
776 - *
777 - * @private
778 - * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
779 - * @param {object} props
780 - * @return {string} Markup of opening tag.
781 - */
782 - _createOpenTagMarkupAndPutListeners: function(transaction, props) {
783 - var ret = '<' + this._currentElement.type;
784 -
785 - for (var propKey in props) {
786 - if (!props.hasOwnProperty(propKey)) {
787 - continue;
788 - }
789 - var propValue = props[propKey];
790 - if (propValue == null) {
791 - continue;
792 - }
793 - if (registrationNameModules.hasOwnProperty(propKey)) {
794 - if (propValue) {
795 - enqueuePutListener(this, propKey, propValue, transaction);
796 - }
797 - } else {
798 - if (propKey === STYLE) {
799 - if (propValue) {
800 - if (__DEV__) {
801 - // See `_updateDOMProperties`. style block
802 - this._previousStyle = propValue;
803 - }
804 - propValue = this._previousStyleCopy = Object.assign({}, props.style);
805 - }
806 - propValue = CSSPropertyOperations.createMarkupForStyles(propValue, this);
807 - }
808 - var markup = null;
809 - if (this._tag != null && isCustomComponent(this._tag, props)) {
810 - if (!RESERVED_PROPS.hasOwnProperty(propKey)) {
811 - markup = DOMPropertyOperations.createMarkupForCustomAttribute(propKey, propValue);
812 - }
813 - } else {
814 - markup = DOMPropertyOperations.createMarkupForProperty(propKey, propValue);
815 - }
816 - if (markup) {
817 - ret += ' ' + markup;
818 - }
819 - }
820 - }
821 -
822 - // For static pages, no need to put React ID and checksum. Saves lots of
823 - // bytes.
824 - if (transaction.renderToStaticMarkup) {
825 - return ret;
826 - }
827 -
828 - if (!this._hostParent) {
829 - ret += ' ' + DOMPropertyOperations.createMarkupForRoot();
830 - }
831 - ret += ' ' + DOMPropertyOperations.createMarkupForID(this._domID);
832 - return ret;
833 - },
834 -
835 - /**
836 - * Creates markup for the content between the tags.
837 - *
838 - * @private
839 - * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
840 - * @param {object} props
841 - * @param {object} context
842 - * @return {string} Content markup.
843 - */
844 - _createContentMarkup: function(transaction, props, context) {
845 - var ret = '';
846 -
847 - // Intentional use of != to avoid catching zero/false.
848 - var innerHTML = props.dangerouslySetInnerHTML;
849 - if (innerHTML != null) {
850 - if (innerHTML.__html != null) {
851 - ret = innerHTML.__html;
852 - }
853 - } else {
854 - var contentToUse =
855 - CONTENT_TYPES[typeof props.children] ? props.children : null;
856 - var childrenToUse = contentToUse != null ? null : props.children;
857 - if (contentToUse != null) {
858 - // TODO: Validate that text is allowed as a child of this node
859 - ret = escapeTextContentForBrowser(contentToUse);
860 - if (__DEV__) {
861 - setAndValidateContentChildDev.call(this, contentToUse);
862 - }
863 - } else if (childrenToUse != null) {
864 - var mountImages = this.mountChildren(
865 - childrenToUse,
866 - transaction,
867 - context
868 - );
869 - ret = mountImages.join('');
870 - }
871 - }
872 - if (newlineEatingTags[this._tag] && ret.charAt(0) === '\n') {
873 - // text/html ignores the first character in these tags if it's a newline
874 - // Prefer to break application/xml over text/html (for now) by adding
875 - // a newline specifically to get eaten by the parser. (Alternately for
876 - // textareas, replacing "^\n" with "\r\n" doesn't get eaten, and the first
877 - // \r is normalized out by HTMLTextAreaElement#value.)
878 - // See: <http://www.w3.org/TR/html-polyglot/#newlines-in-textarea-and-pre>
879 - // See: <http://www.w3.org/TR/html5/syntax.html#element-restrictions>
880 - // See: <http://www.w3.org/TR/html5/syntax.html#newlines>
881 - // See: Parsing of "textarea" "listing" and "pre" elements
882 - // from <http://www.w3.org/TR/html5/syntax.html#parsing-main-inbody>
883 - return '\n' + ret;
884 - } else {
885 - return ret;
886 - }
887 - },
888 -
889 - _createInitialChildren: function(transaction, props, context, lazyTree) {
890 - // Intentional use of != to avoid catching zero/false.
891 - var innerHTML = props.dangerouslySetInnerHTML;
892 - if (innerHTML != null) {
893 - if (innerHTML.__html != null) {
894 - DOMLazyTree.queueHTML(lazyTree, innerHTML.__html);
895 - }
896 - } else {
897 - var contentToUse =
898 - CONTENT_TYPES[typeof props.children] ? props.children : null;
899 - var childrenToUse = contentToUse != null ? null : props.children;
900 - // TODO: Validate that text is allowed as a child of this node
901 - if (contentToUse != null) {
902 - // Avoid setting textContent when the text is empty. In IE11 setting
903 - // textContent on a text area will cause the placeholder to not
904 - // show within the textarea until it has been focused and blurred again.
905 - // https://github.com/facebook/react/issues/6731#issuecomment-254874553
906 - if (contentToUse !== '') {
907 - if (__DEV__) {
908 - setAndValidateContentChildDev.call(this, contentToUse);
909 - }
910 - DOMLazyTree.queueText(lazyTree, contentToUse);
911 - }
912 - } else if (childrenToUse != null) {
913 - var mountImages = this.mountChildren(
914 - childrenToUse,
915 - transaction,
916 - context
917 - );
918 - for (var i = 0; i < mountImages.length; i++) {
919 - DOMLazyTree.queueChild(lazyTree, mountImages[i]);
920 - }
921 - }
922 - }
923 - },
1099
1100 /**
1101 * Receives a next element and updates the component.
@@ -930,298 +1105,78 @@ ReactDOMComponent.Mixin = {
1105 * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
1106 * @param {object} context
1107 */
933 - receiveComponent: function(nextElement, transaction, context) {
934 - var prevElement = this._currentElement;
935 - this._currentElement = nextElement;
936 - this.updateComponent(transaction, prevElement, nextElement, context);
937 - },
1108 + receiveComponent: function(workInProgress : Fiber, nextElement, transaction, context) {
1109 + var prevElement = workInProgress._currentElement;
1110 + workInProgress._currentElement = nextElement;
1111
939 - /**
940 - * Updates a DOM component after it has already been allocated and
941 - * attached to the DOM. Reconciles the root DOM node, then recurses.
942 - *
943 - * @param {ReactReconcileTransaction} transaction
944 - * @param {ReactElement} prevElement
945 - * @param {ReactElement} nextElement
946 - * @internal
947 - * @overridable
948 - */
949 - updateComponent: function(transaction, prevElement, nextElement, context) {
1112 var lastProps = prevElement.props;
951 - var nextProps = this._currentElement.props;
1113 + var nextProps = workInProgress._currentElement.props;
1114
953 - switch (this._tag) {
1115 + switch (workInProgress._tag) {
1116 case 'input':
955 - lastProps = ReactDOMInput.getHostProps(this, lastProps);
956 - nextProps = ReactDOMInput.getHostProps(this, nextProps);
1117 + lastProps = ReactDOMFiberInput.getHostProps(workInProgress, lastProps);
1118 + nextProps = ReactDOMFiberInput.getHostProps(workInProgress, nextProps);
1119 break;
1120 case 'option':
959 - lastProps = ReactDOMOption.getHostProps(this, lastProps);
960 - nextProps = ReactDOMOption.getHostProps(this, nextProps);
1121 + lastProps = ReactDOMFiberOption.getHostProps(workInProgress, lastProps);
1122 + nextProps = ReactDOMFiberOption.getHostProps(workInProgress, nextProps);
1123 break;
1124 case 'select':
963 - lastProps = ReactDOMSelect.getHostProps(this, lastProps);
964 - nextProps = ReactDOMSelect.getHostProps(this, nextProps);
1125 + lastProps = ReactDOMFiberSelect.getHostProps(workInProgress, lastProps);
1126 + nextProps = ReactDOMFiberSelect.getHostProps(workInProgress, nextProps);
1127 break;
1128 case 'textarea':
967 - lastProps = ReactDOMTextarea.getHostProps(this, lastProps);
968 - nextProps = ReactDOMTextarea.getHostProps(this, nextProps);
1129 + lastProps = ReactDOMFiberTextarea.getHostProps(workInProgress, lastProps);
1130 + nextProps = ReactDOMFiberTextarea.getHostProps(workInProgress, nextProps);
1131 break;
1132 default:
1133 if (typeof lastProps.onClick !== 'function' &&
1134 typeof nextProps.onClick === 'function') {
1135 transaction.getReactMountReady().enqueue(
1136 trapClickOnNonInteractiveElement,
975 - this
1137 + workInProgress
1138 );
1139 }
1140 break;
1141 }
1142
981 - assertValidProps(this, nextProps);
982 - var isCustomComponentTag = isCustomComponent(this._tag, nextProps);
983 - this._updateDOMProperties(lastProps, nextProps, transaction, isCustomComponentTag);
984 - this._updateDOMChildren(
1143 + assertValidProps(workInProgress, nextProps);
1144 + var isCustomComponentTag = isCustomComponent(workInProgress._tag, nextProps);
1145 + updateDOMProperties(workInProgress, lastProps, nextProps, transaction, isCustomComponentTag);
1146 + updateDOMChildren(
1147 + workInProgress,
1148 lastProps,
1149 nextProps,
1150 transaction,
1151 context
1152 );
1153
991 - switch (this._tag) {
1154 + switch (workInProgress._tag) {
1155 case 'input':
1156 // Update the wrapper around inputs *after* updating props. This has to
994 - // happen after `_updateDOMProperties`. Otherwise HTML5 input validations
1157 + // happen after `updateDOMProperties`. Otherwise HTML5 input validations
1158 // raise warnings and prevent the new value from being assigned.
996 - ReactDOMInput.updateWrapper(this);
1159 + ReactDOMFiberInput.updateWrapper(workInProgress);
1160 break;
1161 case 'textarea':
999 - ReactDOMTextarea.updateWrapper(this);
1162 + ReactDOMFiberTextarea.updateWrapper(workInProgress);
1163 break;
1164 case 'select':
1165 // <select> value update needs to occur after <option> children
1166 // reconciliation
1004 - transaction.getReactMountReady().enqueue(postUpdateSelectWrapper, this);
1167 + transaction.getReactMountReady().enqueue(postUpdateSelectWrapper, workInProgress);
1168 break;
1169 }
1170 },
1171
1172 /**
1010 - * Reconciles the properties by detecting differences in property values and
1011 - * updating the DOM as necessary. This function is probably the single most
1012 - * critical path for performance optimization.
1013 - *
1014 - * TODO: Benchmark whether checking for changed values in memory actually
1015 - * improves performance (especially statically positioned elements).
1016 - * TODO: Benchmark the effects of putting this at the top since 99% of props
1017 - * do not change for a given reconciliation.
1018 - * TODO: Benchmark areas that can be improved with caching.
1019 - *
1020 - * @private
1021 - * @param {object} lastProps
1022 - * @param {object} nextProps
1023 - * @param {?DOMElement} node
1024 - */
1025 - _updateDOMProperties: function(
1026 - lastProps,
1027 - nextProps,
1028 - transaction,
1029 - isCustomComponentTag
1030 - ) {
1031 - var propKey;
1032 - var styleName;
1033 - var styleUpdates;
1034 - for (propKey in lastProps) {
1035 - if (nextProps.hasOwnProperty(propKey) ||
1036 - !lastProps.hasOwnProperty(propKey) ||
1037 - lastProps[propKey] == null) {
1038 - continue;
1039 - }
1040 - if (propKey === STYLE) {
1041 - var lastStyle = this._previousStyleCopy;
1042 - for (styleName in lastStyle) {
1043 - if (lastStyle.hasOwnProperty(styleName)) {
1044 - styleUpdates = styleUpdates || {};
1045 - styleUpdates[styleName] = '';
1046 - }
1047 - }
1048 - this._previousStyleCopy = null;
1049 - } else if (registrationNameModules.hasOwnProperty(propKey)) {
1050 - if (lastProps[propKey]) {
1051 - // Only call deleteListener if there was a listener previously or
1052 - // else willDeleteListener gets called when there wasn't actually a
1053 - // listener (e.g., onClick={null})
1054 - deleteListener(this, propKey);
1055 - }
1056 - } else if (isCustomComponent(this._tag, lastProps)) {
1057 - if (!RESERVED_PROPS.hasOwnProperty(propKey)) {
1058 - DOMPropertyOperations.deleteValueForAttribute(
1059 - getNode(this),
1060 - propKey
1061 - );
1062 - }
1063 - } else if (
1064 - DOMProperty.properties[propKey] ||
1065 - DOMProperty.isCustomAttribute(propKey)) {
1066 - DOMPropertyOperations.deleteValueForProperty(getNode(this), propKey);
1067 - }
1068 - }
1069 - for (propKey in nextProps) {
1070 - var nextProp = nextProps[propKey];
1071 - var lastProp =
1072 - propKey === STYLE ? this._previousStyleCopy :
1073 - lastProps != null ? lastProps[propKey] : undefined;
1074 - if (!nextProps.hasOwnProperty(propKey) ||
1075 - nextProp === lastProp ||
1076 - nextProp == null && lastProp == null) {
1077 - continue;
1078 - }
1079 - if (propKey === STYLE) {
1080 - if (nextProp) {
1081 - if (__DEV__) {
1082 - checkAndWarnForMutatedStyle(
1083 - this._previousStyleCopy,
1084 - this._previousStyle,
1085 - this
1086 - );
1087 - this._previousStyle = nextProp;
1088 - }
1089 - nextProp = this._previousStyleCopy = Object.assign({}, nextProp);
1090 - } else {
1091 - this._previousStyleCopy = null;
1092 - }
1093 - if (lastProp) {
1094 - // Unset styles on `lastProp` but not on `nextProp`.
1095 - for (styleName in lastProp) {
1096 - if (lastProp.hasOwnProperty(styleName) &&
1097 - (!nextProp || !nextProp.hasOwnProperty(styleName))) {
1098 - styleUpdates = styleUpdates || {};
1099 - styleUpdates[styleName] = '';
1100 - }
1101 - }
1102 - // Update styles that changed since `lastProp`.
1103 - for (styleName in nextProp) {
1104 - if (nextProp.hasOwnProperty(styleName) &&
1105 - lastProp[styleName] !== nextProp[styleName]) {
1106 - styleUpdates = styleUpdates || {};
1107 - styleUpdates[styleName] = nextProp[styleName];
1108 - }
1109 - }
1110 - } else {
1111 - // Relies on `updateStylesByID` not mutating `styleUpdates`.
1112 - styleUpdates = nextProp;
1113 - }
1114 - } else if (registrationNameModules.hasOwnProperty(propKey)) {
1115 - if (nextProp) {
1116 - enqueuePutListener(this, propKey, nextProp, transaction);
1117 - } else if (lastProp) {
1118 - deleteListener(this, propKey);
1119 - }
1120 - } else if (isCustomComponentTag) {
1121 - if (!RESERVED_PROPS.hasOwnProperty(propKey)) {
1122 - DOMPropertyOperations.setValueForAttribute(
1123 - getNode(this),
1124 - propKey,
1125 - nextProp
1126 - );
1127 - }
1128 - } else if (
1129 - DOMProperty.properties[propKey] ||
1130 - DOMProperty.isCustomAttribute(propKey)) {
1131 - var node = getNode(this);
1132 - // If we're updating to null or undefined, we should remove the property
1133 - // from the DOM node instead of inadvertently setting to a string. This
1134 - // brings us in line with the same behavior we have on initial render.
1135 - if (nextProp != null) {
1136 - DOMPropertyOperations.setValueForProperty(node, propKey, nextProp);
1137 - } else {
1138 - DOMPropertyOperations.deleteValueForProperty(node, propKey);
1139 - }
1140 - }
1141 - }
1142 - if (styleUpdates) {
1143 - CSSPropertyOperations.setValueForStyles(
1144 - getNode(this),
1145 - styleUpdates,
1146 - this
1147 - );
1148 - }
1149 - },
1150 -
1151 - /**
1152 - * Reconciles the children with the various properties that affect the
1153 - * children content.
1154 - *
1155 - * @param {object} lastProps
1156 - * @param {object} nextProps
1157 - * @param {ReactReconcileTransaction} transaction
1158 - * @param {object} context
1159 - */
1160 - _updateDOMChildren: function(lastProps, nextProps, transaction, context) {
1161 - var lastContent =
1162 - CONTENT_TYPES[typeof lastProps.children] ? lastProps.children : null;
1163 - var nextContent =
1164 - CONTENT_TYPES[typeof nextProps.children] ? nextProps.children : null;
1165 -
1166 - var lastHtml =
1167 - lastProps.dangerouslySetInnerHTML &&
1168 - lastProps.dangerouslySetInnerHTML.__html;
1169 - var nextHtml =
1170 - nextProps.dangerouslySetInnerHTML &&
1171 - nextProps.dangerouslySetInnerHTML.__html;
1172 -
1173 - // Note the use of `!=` which checks for null or undefined.
1174 - var lastChildren = lastContent != null ? null : lastProps.children;
1175 - var nextChildren = nextContent != null ? null : nextProps.children;
1176 -
1177 - // If we're switching from children to content/html or vice versa, remove
1178 - // the old content
1179 - var lastHasContentOrHtml = lastContent != null || lastHtml != null;
1180 - var nextHasContentOrHtml = nextContent != null || nextHtml != null;
1181 - if (lastChildren != null && nextChildren == null) {
1182 - this.updateChildren(null, transaction, context);
1183 - } else if (lastHasContentOrHtml && !nextHasContentOrHtml) {
1184 - this.updateTextContent('');
1185 - if (__DEV__) {
1186 - ReactInstrumentation.debugTool.onSetChildren(this._debugID, []);
1187 - }
1188 - }
1189 -
1190 - if (nextContent != null) {
1191 - if (lastContent !== nextContent) {
1192 - this.updateTextContent('' + nextContent);
1193 - if (__DEV__) {
1194 - setAndValidateContentChildDev.call(this, nextContent);
1195 - }
1196 - }
1197 - } else if (nextHtml != null) {
1198 - if (lastHtml !== nextHtml) {
1199 - this.updateMarkup('' + nextHtml);
1200 - }
1201 - if (__DEV__) {
1202 - ReactInstrumentation.debugTool.onSetChildren(this._debugID, []);
1203 - }
1204 - } else if (nextChildren != null) {
1205 - if (__DEV__) {
1206 - setAndValidateContentChildDev.call(this, null);
1207 - }
1208 -
1209 - this.updateChildren(nextChildren, transaction, context);
1210 - }
1211 - },
1212 -
1213 - getHostNode: function() {
1214 - return getNode(this);
1215 - },
1216 -
1217 - /**
1218 - * Destroys all event registrations for this instance. Does not remove from
1173 + * Destroys all event registrations for workInProgress instance. Does not remove from
1174 * the DOM. That must be done by the parent.
1175 *
1176 * @internal
1177 */
1178 unmountComponent: function(safely, skipLifecycle) {
1224 - switch (this._tag) {
1179 + switch (workInProgress._tag) {
1180 case 'audio':
1181 case 'form':
1182 case 'iframe':
@@ -1230,7 +1185,7 @@ ReactDOMComponent.Mixin = {
1185 case 'object':
1186 case 'source':
1187 case 'video':
1233 - var listeners = this._wrapperState.listeners;
1188 + var listeners = workInProgress._wrapperState.listeners;
1189 if (listeners) {
1190 for (var i = 0; i < listeners.length; i++) {
1191 listeners[i].remove();
@@ -1239,7 +1194,7 @@ ReactDOMComponent.Mixin = {
1194 break;
1195 case 'input':
1196 case 'textarea':
1242 - inputValueTracking.stopTracking(this);
1197 + inputValueTracking.stopTracking(workInProgress);
1198 break;
1199 case 'html':
1200 case 'head':
@@ -1254,50 +1209,45 @@ ReactDOMComponent.Mixin = {
1209 false,
1210 '<%s> tried to unmount. Because of cross-browser quirks it is ' +
1211 'impossible to unmount some top-level components (eg <html>, ' +
1257 - '<head>, and <body>) reliably and efficiently. To fix this, have a ' +
1212 + '<head>, and <body>) reliably and efficiently. To fix workInProgress, have a ' +
1213 'single top-level component that never unmounts render these ' +
1214 'elements.',
1260 - this._tag
1215 + workInProgress._tag
1216 );
1217 break;
1218 }
1219
1265 - this.unmountChildren(safely, skipLifecycle);
1266 - ReactDOMComponentTree.uncacheNode(this);
1267 - EventPluginHub.deleteAllListeners(this);
1268 - this._rootNodeID = 0;
1269 - this._domID = 0;
1270 - this._wrapperState = null;
1220 + workInProgress.unmountChildren(safely, skipLifecycle);
1221 + ReactDOMComponentTree.uncacheNode(workInProgress);
1222 + EventPluginHub.deleteAllListeners(workInProgress);
1223 + workInProgress._rootNodeID = 0;
1224 + workInProgress._domID = 0;
1225 + workInProgress._wrapperState = null;
1226
1227 if (__DEV__) {
1273 - setAndValidateContentChildDev.call(this, null);
1228 + setAndValidateContentChildDev.call(workInProgress, null);
1229 }
1230 },
1231
1277 - restoreControlledState: function() {
1278 - switch (this._tag) {
1232 + restoreControlledState: function(finishedWork : Fiber) {
1233 + switch (finishedWork.type) {
1234 case 'input':
1280 - ReactDOMInput.restoreControlledState(this);
1235 + ReactDOMFiberInput.restoreControlledState(finishedWork);
1236 return;
1237 case 'textarea':
1283 - ReactDOMTextarea.restoreControlledState(this);
1238 + ReactDOMFiberTextarea.restoreControlledState(finishedWork);
1239 return;
1240 case 'select':
1286 - ReactDOMSelect.restoreControlledState(this);
1241 + ReactDOMFiberSelect.restoreControlledState(finishedWork);
1242 return;
1243 }
1244 },
1245
1291 - getPublicInstance: function() {
1292 - return getNode(this);
1246 + getPublicInstance: function(fiber : Fiber) {
1247 + // If we add wrappers, this could be something deeper.
1248 + return fiber.stateNode;
1249 },
1250
1251 };
1252
1297 -Object.assign(
1298 - ReactDOMComponent.prototype,
1299 - ReactDOMComponent.Mixin,
1300 - ReactMultiChild
1301 -);
1302 -
1303 -module.exports = ReactDOMComponent;
1253 +module.exports = ReactDOMFiberComponent;
src/renderers/dom/fiber/wrappers/ReactDOMFiberInput.js
+1
@@ -7,6 +7,7 @@
7 * of patent rights can be found in the PATENTS file in the same directory.
8 *
9 * @providesModule ReactDOMFiberInput
10 + * @flow
11 */
12
13 'use strict';
src/renderers/dom/fiber/wrappers/ReactDOMFiberOption.js
+1
@@ -7,6 +7,7 @@
7 * of patent rights can be found in the PATENTS file in the same directory.
8 *
9 * @providesModule ReactDOMFiberOption
10 + * @flow
11 */
12
13 'use strict';
src/renderers/dom/fiber/wrappers/ReactDOMFiberSelect.js
+1
@@ -7,6 +7,7 @@
7 * of patent rights can be found in the PATENTS file in the same directory.
8 *
9 * @providesModule ReactDOMFiberSelect
10 + * @flow
11 */
12
13 'use strict';
src/renderers/dom/fiber/wrappers/ReactDOMFiberTextarea.js
+1
@@ -7,6 +7,7 @@
7 * of patent rights can be found in the PATENTS file in the same directory.
8 *
9 * @providesModule ReactDOMFiberTextarea
10 + * @flow
11 */
12
13 'use strict';