Merge pull request #2550 from sebmarkbage/cleanupinternals

Move ComponentEnvironment out of ReactComponent
This commit is contained in:
Sebastian Markbåge
2014-11-17 17:41:32 -08:00
10 changed files with 105 additions and 49 deletions
@@ -15,16 +15,19 @@
var ReactDOMIDOperations = require('ReactDOMIDOperations');
var ReactMount = require('ReactMount');
var ReactReconcileTransaction = require('ReactReconcileTransaction');
/**
* Abstracts away all functionality of `ReactComponent` requires knowledge of
* the browser context.
* Abstracts away all functionality of the reconciler that requires knowledge of
* the browser context. TODO: These callers should be refactored to avoid the
* need for this injection.
*/
var ReactComponentBrowserEnvironment = {
ReactReconcileTransaction: ReactReconcileTransaction,
BackendIDOperations: ReactDOMIDOperations,
processChildrenUpdates:
ReactDOMIDOperations.dangerouslyProcessChildrenUpdates,
replaceNodeWithMarkupByID:
ReactDOMIDOperations.dangerouslyReplaceNodeWithMarkupByID,
/**
* If a particular environment requires that some resources be cleaned up,
+19 -5
View File
@@ -39,6 +39,11 @@ var STYLE = keyOf({style: null});
var ELEMENT_NODE_TYPE = 1;
/**
* Optionally injectable operations for mutating the DOM
*/
var BackendIDOperations = null;
/**
* @param {?object} props
*/
@@ -149,6 +154,7 @@ function ReactDOMComponent(tag) {
this._tag = tag;
this._renderedChildren = null;
this._previousStyleCopy = null;
this._rootNodeID = null;
}
ReactDOMComponent.displayName = 'ReactDOMComponent';
@@ -177,7 +183,7 @@ ReactDOMComponent.Mixin = {
mountDepth,
context
);
this._previousStyleCopy = null;
this._rootNodeID = rootID;
assertValidProps(this._currentElement.props);
var closeTag = omittedCloseTags[this._tag] ? '' : '</' + this._tag + '>';
return (
@@ -370,7 +376,7 @@ ReactDOMComponent.Mixin = {
} else if (
DOMProperty.isStandardName[propKey] ||
DOMProperty.isCustomAttribute(propKey)) {
ReactComponent.BackendIDOperations.deletePropertyByID(
BackendIDOperations.deletePropertyByID(
this._rootNodeID,
propKey
);
@@ -414,7 +420,7 @@ ReactDOMComponent.Mixin = {
} else if (
DOMProperty.isStandardName[propKey] ||
DOMProperty.isCustomAttribute(propKey)) {
ReactComponent.BackendIDOperations.updatePropertyByID(
BackendIDOperations.updatePropertyByID(
this._rootNodeID,
propKey,
nextProp
@@ -422,7 +428,7 @@ ReactDOMComponent.Mixin = {
}
}
if (styleUpdates) {
ReactComponent.BackendIDOperations.updateStylesByID(
BackendIDOperations.updateStylesByID(
this._rootNodeID,
styleUpdates
);
@@ -472,7 +478,7 @@ ReactDOMComponent.Mixin = {
}
} else if (nextHtml != null) {
if (lastHtml !== nextHtml) {
ReactComponent.BackendIDOperations.updateInnerHTMLByID(
BackendIDOperations.updateInnerHTMLByID(
this._rootNodeID,
nextHtml
);
@@ -492,6 +498,8 @@ ReactDOMComponent.Mixin = {
this.unmountChildren();
ReactBrowserEventEmitter.deleteAllListeners(this._rootNodeID);
ReactComponent.Mixin.unmountComponent.call(this);
ReactMount.purgeID(this._rootNodeID);
this._rootNodeID = null;
}
};
@@ -503,4 +511,10 @@ assign(
ReactMultiChild.Mixin
);
ReactDOMComponent.injection = {
injectIDOperations: function(IDOperations) {
ReactDOMComponent.BackendIDOperations = BackendIDOperations = IDOperations;
}
};
module.exports = ReactDOMComponent;
+1 -1
View File
@@ -37,7 +37,7 @@ var INVALID_PROPERTY_ERRORS = {
/**
* Operations used to process updates to DOM nodes. This is made injectable via
* `ReactComponent.BackendIDOperations`.
* `ReactDOMComponent.BackendIDOperations`.
*/
var ReactDOMIDOperations = {
+2 -2
View File
@@ -13,9 +13,9 @@
"use strict";
var DOMPropertyOperations = require('DOMPropertyOperations');
var ReactComponent = require('ReactComponent');
var ReactComponentBrowserEnvironment =
require('ReactComponentBrowserEnvironment');
var ReactDOMComponent = require('ReactDOMComponent');
var assign = require('Object.assign');
var escapeTextForBrowser = require('escapeTextForBrowser');
@@ -100,7 +100,7 @@ assign(ReactDOMTextComponent.prototype, {
// and/or updateComponent to do the actual update for consistency with
// other component types?
this._stringText = nextStringText;
ReactComponent.BackendIDOperations.updateTextContentByID(
ReactDOMComponent.BackendIDOperations.updateTextContentByID(
this._rootNodeID,
nextStringText
);
+4 -1
View File
@@ -28,6 +28,7 @@ var ReactDOMComponent = require('ReactDOMComponent');
var ReactDOMButton = require('ReactDOMButton');
var ReactDOMForm = require('ReactDOMForm');
var ReactDOMImg = require('ReactDOMImg');
var ReactDOMIDOperations = require('ReactDOMIDOperations');
var ReactDOMInput = require('ReactDOMInput');
var ReactDOMOption = require('ReactDOMOption');
var ReactDOMSelect = require('ReactDOMSelect');
@@ -37,6 +38,7 @@ var ReactEventListener = require('ReactEventListener');
var ReactInjection = require('ReactInjection');
var ReactInstanceHandles = require('ReactInstanceHandles');
var ReactMount = require('ReactMount');
var ReactReconcileTransaction = require('ReactReconcileTransaction');
var SelectEventPlugin = require('SelectEventPlugin');
var ServerReactRootIndex = require('ServerReactRootIndex');
var SimpleEventPlugin = require('SimpleEventPlugin');
@@ -102,7 +104,7 @@ function inject() {
ReactInjection.EmptyComponent.injectEmptyComponent('noscript');
ReactInjection.Updates.injectReconcileTransaction(
ReactComponentBrowserEnvironment.ReactReconcileTransaction
ReactReconcileTransaction
);
ReactInjection.Updates.injectBatchingStrategy(
ReactDefaultBatchingStrategy
@@ -115,6 +117,7 @@ function inject() {
);
ReactInjection.Component.injectEnvironment(ReactComponentBrowserEnvironment);
ReactInjection.DOMComponent.injectIDOperations(ReactDOMIDOperations);
if (__DEV__) {
var url = (ExecutionEnvironment.canUseDOM && window.location.href) || '';
+4 -2
View File
@@ -13,18 +13,20 @@
var DOMProperty = require('DOMProperty');
var EventPluginHub = require('EventPluginHub');
var ReactComponent = require('ReactComponent');
var ReactComponentEnvironment = require('ReactComponentEnvironment');
var ReactClass = require('ReactClass');
var ReactEmptyComponent = require('ReactEmptyComponent');
var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
var ReactNativeComponent = require('ReactNativeComponent');
var ReactDOMComponent = require('ReactDOMComponent');
var ReactPerf = require('ReactPerf');
var ReactRootIndex = require('ReactRootIndex');
var ReactUpdates = require('ReactUpdates');
var ReactInjection = {
Component: ReactComponent.injection,
Component: ReactComponentEnvironment.injection,
Class: ReactClass.injection,
DOMComponent: ReactDOMComponent.injection,
DOMProperty: DOMProperty.injection,
EmptyComponent: ReactEmptyComponent.injection,
EventPluginHub: EventPluginHub.injection,
-30
View File
@@ -16,17 +16,6 @@ var ReactRef = require('ReactRef');
var invariant = require('invariant');
var injected = false;
/**
* Optionally injectable environment dependent cleanup hook. (server vs.
* browser etc). Example: A browser system caches DOM nodes based on component
* ID and must remove that cache entry when this instance is unmounted.
*
* @private
*/
var unmountIDFromEnvironment = null;
function attachRef(ref, component, owner) {
if (ref instanceof ReactRef) {
ReactRef.attachRef(ref, component);
@@ -70,20 +59,6 @@ function detachRef(ref, component, owner) {
*/
var ReactComponent = {
injection: {
injectEnvironment: function(ReactComponentEnvironment) {
invariant(
!injected,
'ReactComponent: injectEnvironment() can only be called once.'
);
unmountIDFromEnvironment =
ReactComponentEnvironment.unmountIDFromEnvironment;
ReactComponent.BackendIDOperations =
ReactComponentEnvironment.BackendIDOperations;
injected = true;
}
},
/**
* Injected module that provides ability to mutate individual properties.
* Injected into the base class because many different subclasses need access
@@ -114,7 +89,6 @@ var ReactComponent = {
// We keep the old element and a reference to the pending element
// to track updates.
this._currentElement = element;
this._rootNodeID = null;
this._mountIndex = 0;
this._mountDepth = 0;
},
@@ -140,7 +114,6 @@ var ReactComponent = {
var owner = this._currentElement._owner;
attachRef(ref, this, owner);
}
this._rootNodeID = rootID;
this._mountDepth = mountDepth;
// Effectively: return '';
},
@@ -160,9 +133,6 @@ var ReactComponent = {
if (ref != null) {
detachRef(ref, this, this._currentElement._owner);
}
unmountIDFromEnvironment(this._rootNodeID);
// Reset all fields
this._rootNodeID = null;
},
/**
+57
View File
@@ -0,0 +1,57 @@
/**
* Copyright 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactComponentEnvironment
*/
"use strict";
var invariant = require('invariant');
var injected = false;
var ReactComponentEnvironment = {
/**
* Optionally injectable environment dependent cleanup hook. (server vs.
* browser etc). Example: A browser system caches DOM nodes based on component
* ID and must remove that cache entry when this instance is unmounted.
*/
unmountIDFromEnvironment: null,
/**
* Optionally injectable hook for swapping out mount images in the middle of
* the tree.
*/
replaceNodeWithMarkupByID: null,
/**
* Optionally injectable hook for processing a queue of child updates. Will
* later move into MultiChildComponents.
*/
processChildrenUpdates: null,
injection: {
injectEnvironment: function(environment) {
invariant(
!injected,
'ReactCompositeComponent: injectEnvironment() can only be called once.'
);
ReactComponentEnvironment.unmountIDFromEnvironment =
environment.unmountIDFromEnvironment;
ReactComponentEnvironment.replaceNodeWithMarkupByID =
environment.replaceNodeWithMarkupByID;
ReactComponentEnvironment.processChildrenUpdates =
environment.processChildrenUpdates;
injected = true;
}
},
};
module.exports = ReactComponentEnvironment;
+8 -1
View File
@@ -12,6 +12,7 @@
"use strict";
var ReactComponent = require('ReactComponent');
var ReactComponentEnvironment = require('ReactComponentEnvironment');
var ReactContext = require('ReactContext');
var ReactCurrentOwner = require('ReactCurrentOwner');
var ReactElement = require('ReactElement');
@@ -112,6 +113,8 @@ var ReactCompositeComponentMixin = assign({},
* @internal
*/
construct: function(element) {
this._rootNodeID = null;
this._instance.props = element.props;
this._instance.state = null;
this._instance.context = null;
@@ -168,6 +171,7 @@ var ReactCompositeComponentMixin = assign({},
);
this._context = context;
this._rootNodeID = rootID;
var inst = this._instance;
@@ -259,7 +263,10 @@ var ReactCompositeComponentMixin = assign({},
ReactComponent.Mixin.unmountComponent.call(this);
ReactComponentEnvironment.unmountIDFromEnvironment(this._rootNodeID);
this._context = null;
this._rootNodeID = null;
// Delete the reference from the instance to this internal representation
// which allow the internals to be properly cleaned up even if the user
@@ -780,7 +787,7 @@ var ReactCompositeComponentMixin = assign({},
this._mountDepth + 1,
context
);
ReactComponent.BackendIDOperations.dangerouslyReplaceNodeWithMarkupByID(
ReactComponentEnvironment.replaceNodeWithMarkupByID(
prevComponentID,
nextMarkup
);
+2 -2
View File
@@ -12,7 +12,7 @@
"use strict";
var ReactComponent = require('ReactComponent');
var ReactComponentEnvironment = require('ReactComponentEnvironment');
var ReactMultiChildUpdateTypes = require('ReactMultiChildUpdateTypes');
var flattenChildren = require('flattenChildren');
@@ -136,7 +136,7 @@ function enqueueTextContent(parentID, textContent) {
*/
function processQueue() {
if (updateQueue.length) {
ReactComponent.BackendIDOperations.dangerouslyProcessChildrenUpdates(
ReactComponentEnvironment.processChildrenUpdates(
updateQueue,
markupQueue
);