Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: facebook/react
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 3c7d52c3d6d316d09d5c2479c6851acecccc6325
Choose a base ref
...
head repository: facebook/react
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 1114b6e3f160cc2fdba945ba4e5b52d973c83f22
Choose a head ref
  • 2 commits
  • 28 files changed
  • 1 contributor

Commits on May 2, 2020

  1. Fix tests that only notify most recent listener

    These tests were written in such a way that when a wakeable has multiple
    listeners, only the most recent listener is notified.
    
    I switched them to use a promise instead of mutating a ref.
    acdlite committed May 2, 2020
    Copy the full SHA
    e52b376 View commit details
  2. Initial Lanes implementation

    A refactor of our concurrency and scheduling architecture. Replaces
    the ExpirationTime type with a new concept, called Lanes.
    
    See PR #18796 for more information.
    
    All of the changes I've made in this commit are behind the
    `enableNewReconciler` flag. Merging this to master will not affect the
    open source builds or the build that we ship to Facebook.
    
    The only build that is affected is the `ReactDOMForked` build, which is
    deployed to Facebook **behind an experimental flag (currently disabled
    for all users)**. We will use this flag to gradually roll out the new
    reconciler, and quickly roll it back if we find any problems.
    
    Because we have those protections in place, what I'm aiming for with
    this initial PR is the **smallest possible atomic change that lands
    cleanly and doesn't rely on too many hacks**. The goal has not been to
    get every single test or feature passing, and it definitely is not to
    implement all the features that we intend to build on top of the new
    model. When possible, I have chosen to preserve existing semantics and
    defer changes to follow-up steps. (Listed in the section below.)
    
    (I did not end up having to disable any tests, although if I had, that
    should not have necessarily been a merge blocker.)
    
    For example, even though one of the primary goals of this project is to
    improve our model for parallel Suspense transitions, in this initial
    implementation, I have chosen to keep the same core heuristics for
    sequencing and flushing that existed in the ExpirationTimes model: low
    priority updates cannot finish without also finishing high priority
    ones.
    
    Despite all these precautions, **because the scope of this refactor is
    inherently large, I do expect we will find regressions.** The flip side
    is that I also expect the new model to improve the stability of the
    codebase and make it easier to fix bugs when they arise.
    acdlite committed May 2, 2020
    Copy the full SHA
    1114b6e View commit details
Showing with 1,956 additions and 2,271 deletions.
  1. +51 −52 packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.js
  2. +49 −127 packages/react-reconciler/src/ReactChildFiber.new.js
  3. +48 −72 packages/react-reconciler/src/ReactFiber.new.js
  4. +277 −535 packages/react-reconciler/src/ReactFiberBeginWork.new.js
  5. +20 −30 packages/react-reconciler/src/ReactFiberClassComponent.new.js
  6. +2 −2 packages/react-reconciler/src/ReactFiberCommitWork.new.js
  7. +11 −14 packages/react-reconciler/src/ReactFiberCompleteWork.new.js
  8. +2 −2 packages/react-reconciler/src/ReactFiberDeprecatedEvents.new.js
  9. +0 −92 packages/react-reconciler/src/ReactFiberExpirationTime.new.js
  10. +66 −79 packages/react-reconciler/src/ReactFiberHooks.new.js
  11. +2 −3 packages/react-reconciler/src/ReactFiberHotReloading.new.js
  12. +2 −2 packages/react-reconciler/src/ReactFiberHydrationContext.new.js
  13. +679 −13 packages/react-reconciler/src/ReactFiberLane.js
  14. +36 −79 packages/react-reconciler/src/ReactFiberNewContext.new.js
  15. +3 −3 packages/react-reconciler/src/ReactFiberOffscreenComponent.js
  16. +38 −42 packages/react-reconciler/src/ReactFiberReconciler.new.js
  17. +10 −170 packages/react-reconciler/src/ReactFiberRoot.new.js
  18. +5 −6 packages/react-reconciler/src/ReactFiberSuspenseComponent.new.js
  19. +32 −46 packages/react-reconciler/src/ReactFiberThrow.new.js
  20. +5 −8 packages/react-reconciler/src/ReactFiberUnwindWork.new.js
  21. +454 −733 packages/react-reconciler/src/ReactFiberWorkLoop.new.js
  22. +14 −22 packages/react-reconciler/src/ReactInternalTypes.js
  23. +0 −45 packages/react-reconciler/src/ReactMutableSource.new.js
  24. +21 −22 packages/react-reconciler/src/ReactUpdateQueue.new.js
  25. +86 −40 packages/react-reconciler/src/__tests__/ReactIncrementalUpdates-test.js
  26. +18 −7 packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js
  27. +21 −24 packages/react-reconciler/src/__tests__/ReactSuspenseCallback-test.internal.js
  28. +4 −1 scripts/error-codes/codes.json
Original file line number Diff line number Diff line change
@@ -1306,44 +1306,25 @@ describe('ReactDOMServerHooks', () => {
// State update should trigger the ID to update, which changes the props
// of ChildWithID. This should cause ChildWithID to hydrate before Children

gate(flags => {
if (__DEV__) {
expect(Scheduler).toFlushAndYieldThrough([
'Child with ID',
// Fallbacks are immdiately committed in TestUtils version
// of act
// 'Child with ID',
// 'Child with ID',
'Child One',
'Child Two',
]);
} else if (flags.new) {
// Upgrading a dehyrdating boundary works a little differently in
// the new reconciler. After the update on the boundary is
// scheduled, it waits until the end of the current time slice
// before restarting at the higher priority.
expect(Scheduler).toFlushAndYieldThrough([
'Child with ID',
'Child with ID',
'Child with ID',
'Child with ID',
'Child One',
'Child Two',
]);
} else {
// Whereas the old reconciler relies on a Scheduler hack to
// interrupt the current task. It's not clear if this is any
// better or worse, though. Regardless it's not a big deal since
// the time slices aren't that big.
expect(Scheduler).toFlushAndYieldThrough([
'Child with ID',
'Child with ID',
'Child with ID',
'Child One',
'Child Two',
]);
}
});
expect(Scheduler).toFlushAndYieldThrough(
__DEV__
? [
'Child with ID',
// Fallbacks are immediately committed in TestUtils version
// of act
// 'Child with ID',
// 'Child with ID',
'Child One',
'Child Two',
]
: [
'Child with ID',
'Child with ID',
'Child with ID',
'Child One',
'Child Two',
],
);

expect(child1Ref.current).toBe(null);
expect(childWithIDRef.current).toEqual(
@@ -1691,15 +1672,24 @@ describe('ReactDOMServerHooks', () => {

ReactDOM.createRoot(container, {hydrate: true}).render(<App />);

expect(() =>
expect(() => Scheduler.unstable_flushAll()).toThrow(
if (gate(flags => flags.new)) {
expect(() => Scheduler.unstable_flushAll()).toErrorDev([
'The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. ' +
'Do not read the value directly.',
),
).toErrorDev([
'The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. ' +
'Do not read the value directly.',
]);
]);
} else {
// In the old reconciler, the error isn't surfaced to the user. That
// part isn't important, as long as It warns.
expect(() =>
expect(() => Scheduler.unstable_flushAll()).toThrow(
'The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. ' +
'Do not read the value directly.',
),
).toErrorDev([
'The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. ' +
'Do not read the value directly.',
]);
}
});

it('useOpaqueIdentifier throws if you try to add the result as a number in a child component wrapped in a Suspense', async () => {
@@ -1724,15 +1714,24 @@ describe('ReactDOMServerHooks', () => {

ReactDOM.createRoot(container, {hydrate: true}).render(<App />);

expect(() =>
expect(() => Scheduler.unstable_flushAll()).toThrow(
if (gate(flags => flags.new)) {
expect(() => Scheduler.unstable_flushAll()).toErrorDev([
'The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. ' +
'Do not read the value directly.',
),
).toErrorDev([
'The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. ' +
'Do not read the value directly.',
]);
]);
} else {
// In the old reconciler, the error isn't surfaced to the user. That
// part isn't important, as long as It warns.
expect(() =>
expect(() => Scheduler.unstable_flushAll()).toThrow(
'The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. ' +
'Do not read the value directly.',
),
).toErrorDev([
'The object passed back from useOpaqueIdentifier is meant to be passed through to attributes only. ' +
'Do not read the value directly.',
]);
}
});

it('useOpaqueIdentifier with two opaque identifiers on the same page', () => {
Loading