Skip to content

Commit

Permalink
Schedule passive callbacks before layout effects are invoked (#16713)
Browse files Browse the repository at this point in the history
  • Loading branch information
sebmarkbage authored Sep 9, 2019
1 parent 031eba7 commit cc2492c
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 12 deletions.
23 changes: 11 additions & 12 deletions packages/react-reconciler/src/ReactFiberWorkLoop.js
Original file line number Diff line number Diff line change
Expand Up @@ -1497,14 +1497,6 @@ function commitRoot(root) {
ImmediatePriority,
commitRootImpl.bind(null, root, renderPriorityLevel),
);
// If there are passive effects, schedule a callback to flush them. This goes
// outside commitRootImpl so that it inherits the priority of the render.
if (rootWithPendingPassiveEffects !== null) {
scheduleCallback(NormalPriority, () => {
flushPassiveEffects();
return null;
});
}
return null;
}

Expand Down Expand Up @@ -1858,6 +1850,17 @@ function commitMutationEffects(root: FiberRoot, renderPriorityLevel) {
}
}

if (effectTag & Passive) {
// If there are passive effects, schedule a callback to flush them.
if (!rootDoesHavePassiveEffects) {
rootDoesHavePassiveEffects = true;
scheduleCallback(NormalPriority, () => {
flushPassiveEffects();
return null;
});
}
}

// The following switch statement is only concerned about placement,
// updates, and deletions. To avoid needing to add a case for every possible
// bitmap value, we remove the secondary effects from the effect tag and
Expand Down Expand Up @@ -1943,10 +1946,6 @@ function commitLayoutEffects(
commitAttachRef(nextEffect);
}

if (effectTag & Passive) {
rootDoesHavePassiveEffects = true;
}

resetCurrentDebugFiberInDEV();
nextEffect = nextEffect.nextEffect;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,33 @@ describe('ReactSchedulerIntegration', () => {
expect(Scheduler).toHaveYielded(['Effect clean-up priority: Idle']);
});

it('passive effects are called before Normal-pri scheduled in layout effects', async () => {
const {useEffect, useLayoutEffect} = React;
function Effects({step}) {
useLayoutEffect(() => {
Scheduler.unstable_yieldValue('Layout Effect');
Scheduler.unstable_scheduleCallback(NormalPriority, () =>
Scheduler.unstable_yieldValue(
'Scheduled Normal Callback from Layout Effect',
),
);
});
useEffect(() => {
Scheduler.unstable_yieldValue('Passive Effect');
});
return null;
}
await ReactNoop.act(async () => {
ReactNoop.render(<Effects />);
});
expect(Scheduler).toHaveYielded([
'Layout Effect',
'Passive Effect',
// This callback should be scheduled after the passive effects.
'Scheduled Normal Callback from Layout Effect',
]);
});

it('after completing a level of work, infers priority of the next batch based on its expiration time', () => {
function App({label}) {
Scheduler.unstable_yieldValue(
Expand Down

0 comments on commit cc2492c

Please sign in to comment.