Fix dev/prod mismatch in context === bailout
Fixes #5005.
Ben Alpert committed
Sep 30, 2015 at 16:43 UTC
cf86cd8ebfab28d01e5a2b8dae00e7993fd9d7cc
2 files changed
+54
-11
src/renderers/dom/shared/ReactDOMComponent.js
+31
-11
@@ -480,14 +480,12 @@ function validateDangerousTag(tag) {
480
}
481
}
482
483
-function processChildContext(context, inst) {
484
- if (__DEV__) {
485
- // Pass down our tag name to child components for validation purposes
486
- context = assign({}, context);
487
- var info = context[validateDOMNesting.ancestorInfoContextKey];
488
- context[validateDOMNesting.ancestorInfoContextKey] =
489
- validateDOMNesting.updatedAncestorInfo(info, inst._tag, inst);
490
- }
483
+function processChildContextDev(context, inst) {
484
+ // Pass down our tag name to child components for validation purposes
485
+ context = assign({}, context);
486
+ var info = context[validateDOMNesting.ancestorInfoContextKey];
487
+ context[validateDOMNesting.ancestorInfoContextKey] =
488
+ validateDOMNesting.updatedAncestorInfo(info, inst._tag, inst);
489
return context;
490
}
491
@@ -519,6 +517,10 @@ function ReactDOMComponent(tag) {
517
this._wrapperState = null;
518
this._topLevelWrapper = null;
519
this._nodeWithLegacyProperties = null;
520
+ if (__DEV__) {
521
+ this._unprocessedContextDev = null;
522
+ this._processedContextDev = null;
523
+ }
524
}
525
526
ReactDOMComponent.displayName = 'ReactDOMComponent';
@@ -588,6 +590,12 @@ ReactDOMComponent.Mixin = {
590
}
591
}
592
593
+ if (__DEV__) {
594
+ this._unprocessedContextDev = context;
595
+ this._processedContextDev = processChildContextDev(context, this);
596
+ context = this._processedContextDev;
597
+ }
598
+
599
var mountImage;
600
if (transaction.useCreateElement) {
601
var ownerDocument = context[ReactMount.ownerDocumentContextKey];
@@ -719,7 +727,7 @@ ReactDOMComponent.Mixin = {
727
var mountImages = this.mountChildren(
728
childrenToUse,
729
transaction,
722
- processChildContext(context, this)
730
+ context
731
);
732
ret = mountImages.join('');
733
}
@@ -759,7 +767,7 @@ ReactDOMComponent.Mixin = {
767
var mountImages = this.mountChildren(
768
childrenToUse,
769
transaction,
762
- processChildContext(context, this)
770
+ context
771
);
772
for (var i = 0; i < mountImages.length; i++) {
773
el.appendChild(mountImages[i]);
@@ -821,13 +829,25 @@ ReactDOMComponent.Mixin = {
829
break;
830
}
831
832
+ if (__DEV__) {
833
+ // If the context is reference-equal to the old one, pass down the same
834
+ // processed object so the update bailout in ReactReconciler behaves
835
+ // correctly (and identically in dev and prod). See #5005.
836
+ if (this._unprocessedContextDev !== context) {
837
+ this._unprocessedContextDev = context;
838
+ this._processedContextDev = processChildContextDev(context, this);
839
+ }
840
+ context = this._processedContextDev;
841
+ }
842
+
843
+
844
assertValidProps(this, nextProps);
845
this._updateDOMProperties(lastProps, nextProps, transaction, null);
846
this._updateDOMChildren(
847
lastProps,
848
nextProps,
849
transaction,
830
- processChildContext(context, this)
850
+ context
851
);
852
853
if (!canDefineProperty && this._nodeWithLegacyProperties) {
src/renderers/shared/reconciler/__tests__/ReactCompositeComponent-test.js
+23
@@ -607,6 +607,29 @@ describe('ReactCompositeComponent', function() {
607
expect(ReactDOM.findDOMNode(component).innerHTML).toBe('bar');
608
});
609
610
+ it('should skip update when rerendering element in container', function() {
611
+ var Parent = React.createClass({
612
+ render: function() {
613
+ return <div>{this.props.children}</div>;
614
+ },
615
+ });
616
+
617
+ var childRenders = 0;
618
+ var Child = React.createClass({
619
+ render: function() {
620
+ childRenders++;
621
+ return <div />;
622
+ },
623
+ });
624
+
625
+ var container = document.createElement('div');
626
+ var child = <Child />;
627
+
628
+ ReactDOM.render(<Parent>{child}</Parent>, container);
629
+ ReactDOM.render(<Parent>{child}</Parent>, container);
630
+ expect(childRenders).toBe(1);
631
+ });
632
+
633
it('should pass context when re-rendered for static child', function() {
634
var parentInstance = null;
635
var childInstance = null;