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';