@samitouri / QOS-React / commits / 0dc840a2b9

Fast path for create child

When we don't have any previous fibers we can short cut this path knowing that we will never have any previous child to compare to. This also ensures that we don't create an empty Map in this case.

Sebastian Markbage committed Oct 3, 2016 at 17:51 UTC 0dc840a2b934ce62a061b92c9d02aa09393292d9
1 file changed +72 -1
src/renderers/shared/fiber/ReactChildFiber.js
+72 -1
@@ -88,7 +88,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
88
89 function mapAndDeleteRemainingChildren(
90 returnFiber : Fiber,
91 - currentFirstChild : ?Fiber
91 + currentFirstChild : Fiber
92 ) : Map<string, Fiber> {
93 // Add the remaining children to a temporary map so that we can find them by
94 // keys quickly. At the same time, we'll flag them all for deletion. However,
@@ -261,6 +261,53 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
261 }
262 }
263
264 + function createChild(
265 + returnFiber : Fiber,
266 + newChild : any,
267 + priority : PriorityLevel
268 + ) : ?Fiber {
269 + if (typeof newChild === 'string' || typeof newChild === 'number') {
270 + // Text nodes doesn't have keys. If the previous node is implicitly keyed
271 + // we can continue to replace it without aborting even if it is not a text
272 + // node.
273 + const created = createFiberFromText('' + newChild, priority);
274 + created.return = returnFiber;
275 + return created;
276 + }
277 +
278 + if (typeof newChild === 'object' && newChild !== null) {
279 + switch (newChild.$$typeof) {
280 + case REACT_ELEMENT_TYPE: {
281 + const created = createFiberFromElement(newChild, priority);
282 + created.return = returnFiber;
283 + return created;
284 + }
285 +
286 + case REACT_COROUTINE_TYPE: {
287 + const created = createFiberFromCoroutine(newChild, priority);
288 + created.return = returnFiber;
289 + return created;
290 + }
291 +
292 + case REACT_YIELD_TYPE: {
293 + const reifiedYield = createReifiedYield(newChild);
294 + const created = createFiberFromYield(newChild, priority);
295 + created.output = reifiedYield;
296 + created.return = returnFiber;
297 + return created;
298 + }
299 + }
300 +
301 + if (isArray(newChild) || getIteratorFn(newChild)) {
302 + const created = createFiberFromFragment(newChild, priority);
303 + created.return = returnFiber;
304 + return created;
305 + }
306 + }
307 +
308 + return null;
309 + }
310 +
311 function updateSlot(
312 returnFiber : Fiber,
313 oldFiber : ?Fiber,
@@ -510,6 +557,30 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
557 return resultingFirstChild;
558 }
559
560 + if (!oldFiber) {
561 + // If we don't have any more existing children we can choose a fast path
562 + // since the rest will all be insertions.
563 + for (; newIdx < newChildren.length; newIdx++) {
564 + const newFiber = createChild(
565 + returnFiber,
566 + newChildren[newIdx],
567 + priority
568 + );
569 + if (!newFiber) {
570 + continue;
571 + }
572 + lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx);
573 + if (!previousNewFiber) {
574 + // TODO: Move out of the loop. This only happens for the first run.
575 + resultingFirstChild = newFiber;
576 + } else {
577 + previousNewFiber.sibling = newFiber;
578 + }
579 + previousNewFiber = newFiber;
580 + }
581 + return resultingFirstChild;
582 + }
583 +
584 // Mark all children as deleted and add them to a key map for quick lookups.
585 const existingChildren = mapAndDeleteRemainingChildren(returnFiber, oldFiber);
586