Skip to content

Commit adffa9b

Browse files
yungsterszpao
authored andcommitted
Batch Child Markup Generation
Setting `innerHTML` is slow: http://jsperf.com/react-child-creation/2 This reduces the number of times we set `innerHTML` by batching markup generation in a component tree. As usual, I cleaned up the `ReactMultiChild` module significantly. == Children Reconciliation == When a `ReactNativeComponent` reconciles, it compares currently rendered children, `prevChildren`, with the new children, `nextChildren`. It figures out the shortest series of updates required to render `nextChildren` where each update is one of: - Create nodes for a new child and insert it at an index. - Update an existing node and, if necessary, move it to an index. - Remove an existing node. This serializable series of updates is sent to `ReactDOMIDOperations` where the actions are actually acted on. == Problem == There are two problems: # When a `ReactNativeComponent` renders new children, it sets `innerHTML` once for each contiguous set of children. # Each `ReactNativeComponent` renders its children in isolation, so two components that both render new children will do so separately. For example, consider the following update: React.renderComponent(<div><p><span /></p><p><span /></p></div>, ...); React.renderComponent(<div><p><img /><span /><img /></p><p><img /><span /><img /></p></div>, ...); This will trigger setting `innerHTML` four times. == Solution == Instead of enqueuing the series of updates per component, this diff changes `ReactMultiChild` to enqueue updates per component tree (which works by counting recursive calls to `updateChildren`). Once all updates in the tree are accounted for, we render all markup using a single `innerHTML` set.
1 parent 2e37f65 commit adffa9b

11 files changed

+666
-452
lines changed

src/core/ReactDOMIDOperations.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,17 @@ var ReactDOMIDOperations = {
172172
},
173173

174174
/**
175-
* TODO: We only actually *need* to purge the cache when we remove elements.
176-
* Detect if any elements were removed instead of blindly purging.
175+
* Updates a component's children by processing a series of updates.
176+
*
177+
* @param {array<object>} updates List of update configurations.
178+
* @param {array<string>} markup List of markup strings.
179+
* @internal
177180
*/
178-
manageChildrenByParentID: function(parentID, domOperations) {
179-
var parent = ReactMount.getNode(parentID);
180-
DOMChildrenOperations.manageChildren(parent, domOperations);
181+
dangerouslyProcessChildrenUpdates: function(updates, markup) {
182+
for (var i = 0; i < updates.length; i++) {
183+
updates[i].parentNode = ReactMount.getNode(updates[i].parentID);
184+
}
185+
DOMChildrenOperations.processUpdates(updates, markup);
181186
}
182187

183188
};

src/core/ReactInstanceHandles.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,14 +229,24 @@ function traverseParentPath(start, stop, cb, arg, skipFirst, skipLast) {
229229
*/
230230
var ReactInstanceHandles = {
231231

232-
separator: SEPARATOR,
233-
234232
createReactRootID: function() {
235233
return getReactRootIDString(
236234
Math.ceil(Math.random() * GLOBAL_MOUNT_POINT_MAX)
237235
);
238236
},
239237

238+
/**
239+
* Constructs a React ID by joining a root ID with a name.
240+
*
241+
* @param {string} rootID Root ID of a parent component.
242+
* @param {string} name A component's name (as flattened children).
243+
* @return {string} A React ID.
244+
* @internal
245+
*/
246+
createReactID: function(rootID, name) {
247+
return rootID + SEPARATOR + name;
248+
},
249+
240250
/**
241251
* Gets the DOM ID of the React component that is the root of the tree that
242252
* contains the React component with the supplied DOM ID.

0 commit comments

Comments
 (0)