Skip to content

Commit

Permalink
Add React.startTransition
Browse files Browse the repository at this point in the history
  • Loading branch information
rickhanlonii committed Aug 26, 2020
1 parent c4e0768 commit 379fa48
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -2320,7 +2320,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
};

// @gate experimental
it('top level render', async () => {
it('top level render using withSuspenseConfig', async () => {
function App({page}) {
return (
<Suspense fallback={<Text text="Loading..." />}>
Expand Down Expand Up @@ -2374,6 +2374,55 @@ describe('ReactSuspenseWithNoopRenderer', () => {
expect(ReactNoop.getChildren()).toEqual([span('B')]);
});

// @gate experimental
it('top level render using React.startTransition', async () => {
function App({page}) {
return (
<Suspense fallback={<Text text="Loading..." />}>
<AsyncText text={page} ms={5000} />
</Suspense>
);
}

// Initial render.
React.unstable_startTransition(() => ReactNoop.render(<App page="A" />));

expect(Scheduler).toFlushAndYield(['Suspend! [A]', 'Loading...']);
// Only a short time is needed to unsuspend the initial loading state.
Scheduler.unstable_advanceTime(400);
await advanceTimers(400);
expect(ReactNoop.getChildren()).toEqual([span('Loading...')]);

// Later we load the data.
Scheduler.unstable_advanceTime(5000);
await advanceTimers(5000);
expect(Scheduler).toHaveYielded(['Promise resolved [A]']);
expect(Scheduler).toFlushAndYield(['A']);
expect(ReactNoop.getChildren()).toEqual([span('A')]);

// Start transition.
React.unstable_startTransition(() => ReactNoop.render(<App page="B" />));

expect(Scheduler).toFlushAndYield(['Suspend! [B]', 'Loading...']);
Scheduler.unstable_advanceTime(1000);
await advanceTimers(1000);
// Even after a second, we have still not yet flushed the loading state.
expect(ReactNoop.getChildren()).toEqual([span('A')]);
Scheduler.unstable_advanceTime(11000);
await advanceTimers(11000);
// After the timeout, we do show the loading state.
expect(ReactNoop.getChildren()).toEqual([
hiddenSpan('A'),
span('Loading...'),
]);
// Later we load the data.
Scheduler.unstable_advanceTime(3000);
await advanceTimers(3000);
expect(Scheduler).toHaveYielded(['Promise resolved [B]']);
expect(Scheduler).toFlushAndYield(['B']);
expect(ReactNoop.getChildren()).toEqual([span('B')]);
});

// @gate experimental
it('hooks', async () => {
let transitionToPage;
Expand Down
2 changes: 2 additions & 0 deletions packages/react/index.classic.fb.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ export {
useTransition as unstable_useTransition,
useDeferredValue,
useDeferredValue as unstable_useDeferredValue,
startTransition,
startTransition as unstable_startTransition,
SuspenseList,
SuspenseList as unstable_SuspenseList,
unstable_withSuspenseConfig,
Expand Down
1 change: 1 addition & 0 deletions packages/react/index.experimental.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export {
// exposeConcurrentModeAPIs
useTransition as unstable_useTransition,
useDeferredValue as unstable_useDeferredValue,
startTransition as unstable_startTransition,
SuspenseList as unstable_SuspenseList,
unstable_withSuspenseConfig,
// enableBlocksAPI
Expand Down
1 change: 1 addition & 0 deletions packages/react/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export {
createFactory,
useTransition,
useTransition as unstable_useTransition,
startTransition as unstable_startTransition,
useDeferredValue,
useDeferredValue as unstable_useDeferredValue,
SuspenseList,
Expand Down
2 changes: 2 additions & 0 deletions packages/react/index.modern.fb.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ export {
useTransition as unstable_useTransition,
useDeferredValue,
useDeferredValue as unstable_useDeferredValue,
startTransition,
startTransition as unstable_startTransition,
SuspenseList,
SuspenseList as unstable_SuspenseList,
unstable_withSuspenseConfig,
Expand Down
2 changes: 2 additions & 0 deletions packages/react/src/React.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import {
import {createMutableSource} from './ReactMutableSource';
import ReactSharedInternals from './ReactSharedInternals';
import {createFundamental} from './ReactFundamental';
import {startTransition} from './ReactStartTransition';

// TODO: Move this branching into the other module instead and just re-export.
const createElement = __DEV__ ? createElementWithValidation : createElementProd;
Expand Down Expand Up @@ -107,6 +108,7 @@ export {
createFactory,
// Concurrent Mode
useTransition,
startTransition,
useDeferredValue,
REACT_SUSPENSE_LIST_TYPE as SuspenseList,
REACT_LEGACY_HIDDEN_TYPE as unstable_LegacyHidden,
Expand Down
24 changes: 24 additions & 0 deletions packages/react/src/ReactStartTransition.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

import ReactCurrentBatchConfig from './ReactCurrentBatchConfig';

// Default to an arbitrarily large timeout. Effectively, this is infinite. The
// eventual goal is to never timeout when refreshing already visible content.
const IndefiniteTimeoutConfig = {timeoutMs: 100000};

export function startTransition(scope: () => void) {
const previousConfig = ReactCurrentBatchConfig.suspense;
ReactCurrentBatchConfig.suspense = IndefiniteTimeoutConfig;
try {
scope();
} finally {
ReactCurrentBatchConfig.suspense = previousConfig;
}
}

0 comments on commit 379fa48

Please sign in to comment.