@samitouri / QOS-React-2 / commits / 21dccad47f

Move props equality check into each branch

Now we only bail out once we've entered each branch. This has some repetition with regard to hasContextChanged but I'm hoping we can just get rid of all those branches at some point since they're mostly for backwards compatibility right now.

Sebastian Markbage committed Dec 20, 2016 at 23:47 UTC 21dccad47f26eed4709f59aaf9a897c358f957aa
1 file changed +51 -24
src/renderers/shared/fiber/ReactFiberBeginWork.js
+51 -24
@@ -168,6 +168,15 @@ module.exports = function<T, P, I, TI, C, CX>(
168
169 function updateFragment(current, workInProgress) {
170 var nextChildren = workInProgress.pendingProps;
171 + if (hasContextChanged()) {
172 + // Normally we can bail out on props equality but if context has changed
173 + // we don't do the bailout and we have to reuse existing props instead.
174 + if (nextChildren === null) {
175 + nextChildren = current && current.memoizedProps;
176 + }
177 + } else if (nextChildren === null || workInProgress.memoizedProps === nextChildren) {
178 + return bailoutOnAlreadyFinishedWork(current, workInProgress);
179 + }
180 reconcileChildren(current, workInProgress, nextChildren);
181 return workInProgress.child;
182 }
@@ -282,8 +291,22 @@ module.exports = function<T, P, I, TI, C, CX>(
291 }
292
293 function updateHostComponent(current, workInProgress) {
285 - const nextProps = workInProgress.pendingProps;
294 + let nextProps = workInProgress.pendingProps;
295 const prevProps = current ? current.memoizedProps : null;
296 + const memoizedProps = workInProgress.memoizedProps;
297 + if (hasContextChanged()) {
298 + // Normally we can bail out on props equality but if context has changed
299 + // we don't do the bailout and we have to reuse existing props instead.
300 + if (nextProps === null) {
301 + nextProps = prevProps;
302 + if (!nextProps) {
303 + throw new Error('We should always have pending or current props.');
304 + }
305 + }
306 + } else if (nextProps === null || memoizedProps === nextProps) {
307 + return bailoutOnAlreadyFinishedWork(current, workInProgress);
308 + }
309 +
310 let nextChildren = nextProps.children;
311 const isDirectTextChild = shouldSetTextContent(nextProps);
312
@@ -376,11 +399,20 @@ module.exports = function<T, P, I, TI, C, CX>(
399 }
400
401 function updateCoroutineComponent(current, workInProgress) {
379 - var coroutine = (workInProgress.pendingProps : ?ReactCoroutine);
380 - if (!coroutine) {
381 - throw new Error('Should be resolved by now');
402 + var nextCoroutine = (workInProgress.pendingProps : null | ReactCoroutine);
403 + if (hasContextChanged()) {
404 + // Normally we can bail out on props equality but if context has changed
405 + // we don't do the bailout and we have to reuse existing props instead.
406 + if (nextCoroutine === null) {
407 + nextCoroutine = current && current.memoizedProps;
408 + if (!nextCoroutine) {
409 + throw new Error('We should always have pending or current props.');
410 + }
411 + }
412 + } else if (nextCoroutine === null || workInProgress.memoizedProps === nextCoroutine) {
413 + return bailoutOnAlreadyFinishedWork(current, workInProgress);
414 }
383 - reconcileChildren(current, workInProgress, coroutine.children);
415 + reconcileChildren(current, workInProgress, nextCoroutine.children);
416 // This doesn't take arbitrary time so we could synchronously just begin
417 // eagerly do the work of workInProgress.child as an optimization.
418 return workInProgress.child;
@@ -389,7 +421,20 @@ module.exports = function<T, P, I, TI, C, CX>(
421 function updatePortalComponent(current, workInProgress) {
422 pushHostContainer(workInProgress.stateNode.containerInfo);
423 const priorityLevel = workInProgress.pendingWorkPriority;
392 - const nextChildren = workInProgress.pendingProps;
424 + let nextChildren = workInProgress.pendingProps;
425 + if (hasContextChanged()) {
426 + // Normally we can bail out on props equality but if context has changed
427 + // we don't do the bailout and we have to reuse existing props instead.
428 + if (nextChildren === null) {
429 + nextChildren = current && current.memoizedProps;
430 + if (!nextChildren) {
431 + throw new Error('We should always have pending or current props.');
432 + }
433 + }
434 + } else if (nextChildren === null || workInProgress.memoizedProps === nextChildren) {
435 + return bailoutOnAlreadyFinishedWork(current, workInProgress);
436 + }
437 +
438 if (!current) {
439 // Portals are special because we don't append the children during mount
440 // but at commit. Therefore we need to track insertions which the normal
@@ -536,24 +581,6 @@ module.exports = function<T, P, I, TI, C, CX>(
581 workInProgress.child = workInProgress.progressedChild;
582 }
583
539 - const pendingProps = workInProgress.pendingProps;
540 - const memoizedProps = workInProgress.memoizedProps;
541 - const updateQueue = workInProgress.updateQueue;
542 -
543 - // This is kept as a single expression to take advantage of short-circuiting.
544 - const hasNewProps = (
545 - pendingProps !== null && ( // hasPendingProps && (
546 - memoizedProps === null || // hasNoMemoizedProps ||
547 - pendingProps !== memoizedProps // memoizedPropsDontMatch
548 - ) // )
549 - );
550 - if (!hasNewProps) {
551 - const hasUpdate = updateQueue && hasPendingUpdate(updateQueue, priorityLevel);
552 - if (!hasUpdate && !hasContextChanged()) {
553 - return bailoutOnAlreadyFinishedWork(current, workInProgress);
554 - }
555 - }
556 -
584 switch (workInProgress.tag) {
585 case IndeterminateComponent:
586 return mountIndeterminateComponent(current, workInProgress, priorityLevel);