@samitouri / QOS-React-2 / commits / 8592eacbf9
Fork 0

The library for web and native user interfaces.

Use Node Cache in ReactComponent

There are currently two places where we lookup and cache nodes: `ReactDOMNodeCache` and `ReactComponent`. Instead, we should just consolidate caches and make `ReactComponent` use `ReactDOMNodeCache`.

CommitSyncScript committed Jun 14, 2013 at 16:22 UTC 8592eacbf9c94e48c0133c2124414f5910ba42b9
4 files changed +66 -43
src/core/ReactComponent.js
+3 -16
@@ -18,9 +18,9 @@
18
19 "use strict";
20
21 -var ExecutionEnvironment = require('ExecutionEnvironment');
21 var ReactCurrentOwner = require('ReactCurrentOwner');
22 var ReactDOMIDOperations = require('ReactDOMIDOperations');
23 +var ReactDOMNodeCache = require('ReactDOMNodeCache');
24 var ReactMount = require('ReactMount');
25 var ReactOwner = require('ReactOwner');
26 var ReactReconcileTransaction = require('ReactReconcileTransaction');
@@ -207,24 +207,11 @@ var ReactComponent = {
207 * @protected
208 */
209 getDOMNode: function() {
210 - invariant(
211 - ExecutionEnvironment.canUseDOM,
212 - 'getDOMNode(): The DOM is not supported in the current environment.'
213 - );
210 invariant(
211 this.isMounted(),
212 'getDOMNode(): A component must be mounted to have a DOM node.'
213 );
218 - var rootNode = this._rootNode;
219 - if (!rootNode) {
220 - rootNode = document.getElementById(this._rootNodeID);
221 - if (!rootNode) {
222 - // TODO: Log the frequency that we reach this path.
223 - rootNode = ReactMount.findReactRenderedDOMNodeSlow(this._rootNodeID);
224 - }
225 - this._rootNode = rootNode;
226 - }
227 - return rootNode;
214 + return ReactDOMNodeCache.getNodeByID(this._rootNodeID);
215 },
216
217 /**
@@ -372,7 +359,7 @@ var ReactComponent = {
359 if (props.ref != null) {
360 ReactOwner.removeComponentAsRefFrom(this, props.ref, props[OWNER]);
361 }
375 - this._rootNode = null;
362 + ReactDOMNodeCache.purgeID(this._rootNodeID);
363 this._rootNodeID = null;
364 this._lifeCycleState = ComponentLifeCycle.UNMOUNTED;
365 },
src/core/ReactDOMIDOperations.js
+8 -8
@@ -66,7 +66,7 @@ var ReactDOMIDOperations = {
66 * @internal
67 */
68 updatePropertyByID: function(id, name, value) {
69 - var node = ReactDOMNodeCache.getCachedNodeByID(id);
69 + var node = ReactDOMNodeCache.getNodeByID(id);
70 invariant(
71 !INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
72 'updatePropertyByID(...): %s',
@@ -84,7 +84,7 @@ var ReactDOMIDOperations = {
84 * @internal
85 */
86 deletePropertyByID: function(id, name, value) {
87 - var node = ReactDOMNodeCache.getCachedNodeByID(id);
87 + var node = ReactDOMNodeCache.getNodeByID(id);
88 invariant(
89 !INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
90 'updatePropertyByID(...): %s',
@@ -121,7 +121,7 @@ var ReactDOMIDOperations = {
121 * @internal
122 */
123 updateStylesByID: function(id, styles) {
124 - var node = ReactDOMNodeCache.getCachedNodeByID(id);
124 + var node = ReactDOMNodeCache.getNodeByID(id);
125 CSSPropertyOperations.setValueForStyles(node, styles);
126 },
127
@@ -133,7 +133,7 @@ var ReactDOMIDOperations = {
133 * @internal
134 */
135 updateInnerHTMLByID: function(id, html) {
136 - var node = ReactDOMNodeCache.getCachedNodeByID(id);
136 + var node = ReactDOMNodeCache.getNodeByID(id);
137 // HACK: IE8- normalize whitespace in innerHTML, removing leading spaces.
138 // @see quirksmode.org/bugreports/archives/2004/11/innerhtml_and_t.html
139 node.innerHTML = (html && html.__html || '').replace(/^ /g, ' ');
@@ -147,7 +147,7 @@ var ReactDOMIDOperations = {
147 * @internal
148 */
149 updateTextContentByID: function(id, content) {
150 - var node = ReactDOMNodeCache.getCachedNodeByID(id);
150 + var node = ReactDOMNodeCache.getNodeByID(id);
151 node[textContentAccessor] = content;
152 },
153
@@ -160,7 +160,7 @@ var ReactDOMIDOperations = {
160 * @see {Danger.dangerouslyReplaceNodeWithMarkup}
161 */
162 dangerouslyReplaceNodeWithMarkupByID: function(id, markup) {
163 - var node = ReactDOMNodeCache.getCachedNodeByID(id);
163 + var node = ReactDOMNodeCache.getNodeByID(id);
164 DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup(node, markup);
165 ReactDOMNodeCache.purgeEntireCache();
166 },
@@ -170,13 +170,13 @@ var ReactDOMIDOperations = {
170 * Detect if any elements were removed instead of blindly purging.
171 */
172 manageChildrenByParentID: function(parentID, domOperations) {
173 - var parent = ReactDOMNodeCache.getCachedNodeByID(parentID);
173 + var parent = ReactDOMNodeCache.getNodeByID(parentID);
174 DOMChildrenOperations.manageChildren(parent, domOperations);
175 ReactDOMNodeCache.purgeEntireCache();
176 },
177
178 setTextNodeValueAtIndexByParentID: function(parentID, index, value) {
179 - var parent = ReactDOMNodeCache.getCachedNodeByID(parentID);
179 + var parent = ReactDOMNodeCache.getNodeByID(parentID);
180 DOMChildrenOperations.setTextNodeValueAtIndex(parent, index, value);
181 }
182
src/core/ReactDOMNodeCache.js
+51 -15
@@ -14,39 +14,75 @@
14 * limitations under the License.
15 *
16 * @providesModule ReactDOMNodeCache
17 + * @typechecks
18 */
19
20 "use strict";
21
22 +var ExecutionEnvironment = require('ExecutionEnvironment');
23 var ReactMount = require('ReactMount');
24
25 +var invariant = require('invariant');
26 +
27 var nodeCache = {};
28
29 /**
30 * DOM node cache only intended for use by React. Placed into a shared module so
31 * that both read and write utilities may benefit from a shared cache.
32 + *
33 + * @internal
34 */
35 var ReactDOMNodeCache = {
36 +
37 + /**
38 + * Finds the node with the supplied React-generated DOM ID.
39 + *
40 + * @param {string} id A React-generated DOM ID.
41 + * @return {?DOMElement} DOM node with the suppled `id`.
42 + * @internal
43 + */
44 + getNodeByID: function(id) {
45 + invariant(
46 + ExecutionEnvironment.canUseDOM,
47 + 'getDOMNode(): The DOM is not supported in the current environment.'
48 + );
49 + if (!nodeCache[id]) {
50 + nodeCache[id] =
51 + document.getElementById(id) ||
52 + ReactMount.findReactRenderedDOMNodeSlow(id);
53 + }
54 + return nodeCache[id];
55 + },
56 +
57 /**
31 - * Releases fast id lookups (node/style cache). This implementation is
32 - * aggressive with purging because the bookkeeping associated with doing fine
33 - * grained deleted from the cache may outweight the benefits of the cache. The
34 - * heuristic that should be used to purge is 'any time anything is deleted'.
35 - * Typically this means that a large amount of content is being replaced and
36 - * several elements would need purging regardless. It's also a time when an
37 - * application is likely not in the middle of a "smooth operation" (such as
38 - * animating/scrolling).
58 + * Purges the supplied ID from cache.
59 + *
60 + * @param {string} id A React-generated DOM ID.
61 + * @internal
62 + */
63 + purgeID: function(id) {
64 + nodeCache[id] = null;
65 + },
66 +
67 + /**
68 + * Purges the entire node cache used for fast ID lookups.
69 + *
70 + * This implementation is aggressive with purging because the bookkeeping
71 + * associated with doing fine-grained deletes from the cache may outweight the
72 + * benefits of the cache.
73 + *
74 + * The heuristic used to purge is 'any time anything is deleted'. Typically
75 + * this means that a large amount of content is being replaced and several
76 + * elements would need purging regardless. This is also when applications are
77 + * less likely to be in the middle of "smooth operations" such as animations
78 + * or scrolling.
79 + *
80 + * @internal
81 */
82 purgeEntireCache: function() {
83 nodeCache = {};
42 - return nodeCache;
43 - },
44 - getCachedNodeByID: function(id) {
45 - return nodeCache[id] ||
46 - (nodeCache[id] =
47 - document.getElementById(id) ||
48 - ReactMount.findReactRenderedDOMNodeSlow(id));
84 }
85 +
86 };
87
88 module.exports = ReactDOMNodeCache;
src/core/__tests__/ReactDOMIDOperations-test.js
+4 -4
@@ -27,7 +27,7 @@ describe('ReactDOMIDOperations', function() {
27 var keyOf = require('keyOf');
28
29 it('should disallow updating special properties', function() {
30 - spyOn(ReactDOMNodeCache, "getCachedNodeByID");
30 + spyOn(ReactDOMNodeCache, "getNodeByID");
31 spyOn(DOMPropertyOperations, "setValueForProperty");
32
33 expect(function() {
@@ -39,7 +39,7 @@ describe('ReactDOMIDOperations', function() {
39 }).toThrow();
40
41 expect(
42 - ReactDOMNodeCache.getCachedNodeByID.argsForCall[0][0]
42 + ReactDOMNodeCache.getNodeByID.argsForCall[0][0]
43 ).toBe('testID');
44
45 expect(
@@ -49,7 +49,7 @@ describe('ReactDOMIDOperations', function() {
49
50 it('should update innerHTML and special-case whitespace', function() {
51 var stubNode = document.createElement('div');
52 - spyOn(ReactDOMNodeCache, "getCachedNodeByID").andReturn(stubNode);
52 + spyOn(ReactDOMNodeCache, "getNodeByID").andReturn(stubNode);
53
54 ReactDOMIDOperations.updateInnerHTMLByID(
55 'testID',
@@ -57,7 +57,7 @@ describe('ReactDOMIDOperations', function() {
57 );
58
59 expect(
60 - ReactDOMNodeCache.getCachedNodeByID.argsForCall[0][0]
60 + ReactDOMNodeCache.getNodeByID.argsForCall[0][0]
61 ).toBe('testID');
62
63 expect(stubNode.innerHTML).toBe(' testContent');