function moveCoroutineToHandlerPhase(current : ?Fiber, workInProgress : Fiber) { var coroutine = (workInProgress.pendingProps : ?ReactCoroutine); if (!coroutine) { throw new Error('Should be resolved by now'); } // First step of the coroutine has completed. Now we need to do the second. // TODO: It would be nice to have a multi stage coroutine represented by a // single component, or at least tail call optimize nested ones. Currently // that requires additional fields that we don't want to add to the fiber. // So this requires nested handlers. // Note: This doesn't mutate the alternate node. I don't think it needs to // since this stage is reset for every pass. workInProgress.tag = CoroutineHandlerPhase; // Build up the yields. // TODO: Compare this to a generator or opaque helpers like Children. var yields : Array<ReifiedYield> = []; appendAllYields(yields, workInProgress); var fn = coroutine.handler; var props = coroutine.props; var nextChildren = fn(props, yields); var currentFirstChild = current ? current.stateNode : null; // Inherit the priority of the returnFiber. const priority = workInProgress.pendingWorkPriority; workInProgress.stateNode = reconcileChildFibers( workInProgress, currentFirstChild, nextChildren, priority ); return workInProgress.stateNode; }
function reconcileChildrenAtPriority(current, workInProgress, nextChildren, priorityLevel) { // At this point any memoization is no longer valid since we'll have changed // the children. workInProgress.memoizedProps = null; if (current && current.child === workInProgress.child) { // If the current child is the same as the work in progress, it means that // we haven't yet started any work on these children. Therefore, we use // the clone algorithm to create a copy of all the current children. workInProgress.child = reconcileChildFibers( workInProgress, workInProgress.child, nextChildren, priorityLevel ); } else { // If, on the other hand, we don't have a current fiber or if it is // already using a clone, that means we've already begun some work on this // tree and we can continue where we left off by reconciling against the // existing children. workInProgress.child = reconcileChildFibersInPlace( workInProgress, workInProgress.child, nextChildren, priorityLevel ); } markChildAsProgressed(current, workInProgress, priorityLevel); }
function moveCoroutineToHandlerPhase(workInProgress : Fiber) { var coroutine = (workInProgress.input : ?ReactCoroutine); if (!coroutine) { throw new Error('Should be resolved by now'); } // First step of the coroutine has completed. Now we need to do the second. // TODO: It would be nice to have a multi stage coroutine represented by a // single component, or at least tail call optimize nested ones. Currently // that requires additional fields that we don't want to add to the fiber. // So this requires nested handlers. // Note: This doesn't mutate the alternate node. I don't think it needs to // since this stage is reset for every pass. workInProgress.tag = CoroutineHandlerPhase; // Build up the yields. // TODO: Compare this to a generator or opaque helpers like Children. var yields : Array<ReifiedYield> = []; var child = workInProgress.child; while (child) { recursivelyFillYields(yields, child.output); child = child.sibling; } var fn = coroutine.handler; var props = coroutine.props; var nextChildren = fn(props, yields); workInProgress.stateNode = ReactChildFiber.reconcileChildFibers( workInProgress, workInProgress.stateNode, nextChildren ); return workInProgress.stateNode; }
function updateCoroutineComponent( current, workInProgress, renderExpirationTime, ) { var nextCoroutine = (workInProgress.pendingProps: null | ReactCoroutine); if (hasContextChanged()) { // Normally we can bail out on props equality but if context has changed // we don't do the bailout and we have to reuse existing props instead. if (nextCoroutine === null) { nextCoroutine = current && current.memoizedProps; invariant( nextCoroutine !== null, 'We should always have pending or current props. This error is ' + 'likely caused by a bug in React. Please file an issue.', ); } } else if ( nextCoroutine === null || workInProgress.memoizedProps === nextCoroutine ) { nextCoroutine = workInProgress.memoizedProps; // TODO: When bailing out, we might need to return the stateNode instead // of the child. To check it for work. // return bailoutOnAlreadyFinishedWork(current, workInProgress); } const nextChildren = nextCoroutine.children; // The following is a fork of reconcileChildrenAtExpirationTime but using // stateNode to store the child. if (current === null) { workInProgress.stateNode = mountChildFibersInPlace( workInProgress, workInProgress.stateNode, nextChildren, renderExpirationTime, ); } else if (current.child === workInProgress.child) { workInProgress.stateNode = reconcileChildFibers( workInProgress, workInProgress.stateNode, nextChildren, renderExpirationTime, ); } else { workInProgress.stateNode = reconcileChildFibersInPlace( workInProgress, workInProgress.stateNode, nextChildren, renderExpirationTime, ); } memoizeProps(workInProgress, nextCoroutine); // This doesn't take arbitrary time so we could synchronously just begin // eagerly do the work of workInProgress.child as an optimization. return workInProgress.stateNode; }
function reconcileChildrenAtPriority( current, workInProgress, nextChildren, priorityLevel, ) { // At this point any memoization is no longer valid since we'll have changed // the children. workInProgress.memoizedProps = null; if (current === null) { // If this is a fresh new component that hasn't been rendered yet, we // won't update its child set by applying minimal side-effects. Instead, // we will add them all to the child before it gets rendered. That means // we can optimize this reconciliation pass by not tracking side-effects. workInProgress.child = mountChildFibersInPlace( workInProgress, workInProgress.child, nextChildren, priorityLevel, ); } else if (current.child === workInProgress.child) { // If the current child is the same as the work in progress, it means that // we haven't yet started any work on these children. Therefore, we use // the clone algorithm to create a copy of all the current children. // If we had any progressed work already, that is invalid at this point so // let's throw it out. clearDeletions(workInProgress); workInProgress.child = reconcileChildFibers( workInProgress, workInProgress.child, nextChildren, priorityLevel, ); transferDeletions(workInProgress); } else { // If, on the other hand, it is already using a clone, that means we've // already begun some work on this tree and we can continue where we left // off by reconciling against the existing children. workInProgress.child = reconcileChildFibersInPlace( workInProgress, workInProgress.child, nextChildren, priorityLevel, ); transferDeletions(workInProgress); } markChildAsProgressed(current, workInProgress, priorityLevel); }
function moveCoroutineToHandlerPhase( current: Fiber | null, workInProgress: Fiber, ) { var coroutine = (workInProgress.memoizedProps: ?ReactCoroutine); invariant( coroutine, 'Should be resolved by now. This error is likely caused by a bug in ' + 'React. Please file an issue.', ); // First step of the coroutine has completed. Now we need to do the second. // TODO: It would be nice to have a multi stage coroutine represented by a // single component, or at least tail call optimize nested ones. Currently // that requires additional fields that we don't want to add to the fiber. // So this requires nested handlers. // Note: This doesn't mutate the alternate node. I don't think it needs to // since this stage is reset for every pass. workInProgress.tag = CoroutineHandlerPhase; // Build up the yields. // TODO: Compare this to a generator or opaque helpers like Children. var yields: Array<mixed> = []; appendAllYields(yields, workInProgress); var fn = coroutine.handler; var props = coroutine.props; var nextChildren = fn(props, yields); var currentFirstChild = current !== null ? current.child : null; // Inherit the priority of the returnFiber. const priority = workInProgress.pendingWorkPriority; workInProgress.child = reconcileChildFibers( workInProgress, currentFirstChild, nextChildren, priority, ); markChildAsProgressed(current, workInProgress, priority); return workInProgress.child; }