diff --git a/scripts/fiber/tests-passing.txt b/scripts/fiber/tests-passing.txt index de017935ce..3bd15a1703 100644 --- a/scripts/fiber/tests-passing.txt +++ b/scripts/fiber/tests-passing.txt @@ -751,11 +751,11 @@ src/renderers/dom/fiber/__tests__/ReactDOMFiber-test.js src/renderers/dom/fiber/__tests__/ReactDOMFiberAsync-test.js * renders synchronously by default -* throws when calling async APIs when feature flag is disabled -* unstable_asyncUpdates creates an async subtree -* updates inside an async subtree are async by default +* renders syncrhonously when feature flag is disabled * unstable_asyncUpdates at the root makes the entire tree async * updates inside an async tree are async by default +* unstable_asyncUpdates creates an async subtree +* updates inside an async subtree are async by default src/renderers/dom/shared/__tests__/CSSProperty-test.js * should generate browser prefixes for its `isUnitlessNumber` diff --git a/src/renderers/dom/fiber/ReactDOMFiber.js b/src/renderers/dom/fiber/ReactDOMFiber.js index 7dd9c8a3f2..f4710f49e3 100644 --- a/src/renderers/dom/fiber/ReactDOMFiber.js +++ b/src/renderers/dom/fiber/ReactDOMFiber.js @@ -364,7 +364,6 @@ var DOMRenderer = ReactFiberReconciler({ scheduleDeferredCallback: ReactDOMFrameScheduling.rIC, useSyncScheduling: !ReactDOMFeatureFlags.fiberAsyncScheduling, - enableAsyncSubtreeAPI: ReactDOMFeatureFlags.enableAsyncSubtreeAPI, }); ReactGenericBatching.injection.injectFiberBatchedUpdates( diff --git a/src/renderers/dom/fiber/__tests__/ReactDOMFiberAsync-test.js b/src/renderers/dom/fiber/__tests__/ReactDOMFiberAsync-test.js index 746de0e830..9f780ac186 100644 --- a/src/renderers/dom/fiber/__tests__/ReactDOMFiberAsync-test.js +++ b/src/renderers/dom/fiber/__tests__/ReactDOMFiberAsync-test.js @@ -1,5 +1,6 @@ var React = require('react'); var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags'); +var ReactFeatureFlags = require('ReactFeatureFlags'); var ReactDOM; @@ -23,21 +24,69 @@ describe('ReactDOMFiberAsync', () => { }); if (ReactDOMFeatureFlags.useFiber) { - it('throws when calling async APIs when feature flag is disabled', () => { - expect(() => { - ReactDOM.unstable_asyncRender(
Hi
, container); - }).toThrow('ReactDOM.unstable_asyncRender is not a function'); + it('renders syncrhonously when feature flag is disabled', () => { + function Async(props) { + return props.children; + } + Async.unstable_asyncUpdates = true; + ReactDOM.render(
Hi
, container); + expect(container.textContent).toEqual('Hi'); + + ReactDOM.render(
Bye
, container); + expect(container.textContent).toEqual('Bye'); }); describe('with feature flag enabled', () => { beforeEach(() => { jest.resetModules(); - ReactDOMFeatureFlags = require('ReactDOMFeatureFlags'); + ReactFeatureFlags = require('ReactFeatureFlags'); container = document.createElement('div'); - ReactDOMFeatureFlags.enableAsyncSubtreeAPI = true; + ReactFeatureFlags.enableAsyncSubtreeAPI = true; ReactDOM = require('react-dom'); }); + it('unstable_asyncUpdates at the root makes the entire tree async', () => { + function Async(props) { + return props.children; + } + Async.unstable_asyncUpdates = true; + ReactDOM.render(
Hi
, container); + expect(container.textContent).toEqual(''); + jest.runAllTimers(); + expect(container.textContent).toEqual('Hi'); + + ReactDOM.render(
Bye
, container); + expect(container.textContent).toEqual('Hi'); + jest.runAllTimers(); + expect(container.textContent).toEqual('Bye'); + }); + + it('updates inside an async tree are async by default', () => { + function Async(props) { + return props.children; + } + Async.unstable_asyncUpdates = true; + + let instance; + class Component extends React.Component { + state = {step: 0}; + render() { + instance = this; + return
{this.state.step}
; + } + } + + ReactDOM.render(, container); + expect(container.textContent).toEqual(''); + jest.runAllTimers(); + expect(container.textContent).toEqual('0'); + + instance.setState({step: 1}); + expect(container.textContent).toEqual('0'); + jest.runAllTimers(); + expect(container.textContent).toEqual('1'); + }); + it('unstable_asyncUpdates creates an async subtree', () => { let instance; class Component extends React.Component { @@ -81,48 +130,6 @@ describe('ReactDOMFiberAsync', () => { jest.runAllTimers(); expect(container.textContent).toEqual('1'); }); - - it('unstable_asyncUpdates at the root makes the entire tree async', () => { - function Async(props) { - return props.children; - } - Async.unstable_asyncUpdates = true; - ReactDOM.render(
Hi
, container); - expect(container.textContent).toEqual(''); - jest.runAllTimers(); - expect(container.textContent).toEqual('Hi'); - - ReactDOM.render(
Bye
, container); - expect(container.textContent).toEqual('Hi'); - jest.runAllTimers(); - expect(container.textContent).toEqual('Bye'); - }); - - it('updates inside an async tree are async by default', () => { - function Async(props) { - return props.children; - } - Async.unstable_asyncUpdates = true; - - let instance; - class Component extends React.Component { - state = {step: 0}; - render() { - instance = this; - return
{this.state.step}
; - } - } - - ReactDOM.render(, container); - expect(container.textContent).toEqual(''); - jest.runAllTimers(); - expect(container.textContent).toEqual('0'); - - instance.setState({step: 1}); - expect(container.textContent).toEqual('0'); - jest.runAllTimers(); - expect(container.textContent).toEqual('1'); - }); }); } }); diff --git a/src/renderers/dom/shared/ReactDOMFeatureFlags.js b/src/renderers/dom/shared/ReactDOMFeatureFlags.js index 7fb34ceb23..1e21bca758 100644 --- a/src/renderers/dom/shared/ReactDOMFeatureFlags.js +++ b/src/renderers/dom/shared/ReactDOMFeatureFlags.js @@ -13,7 +13,6 @@ var ReactDOMFeatureFlags = { fiberAsyncScheduling: false, - enableAsyncSubtreeAPI: false, useCreateElement: true, useFiber: true, }; diff --git a/src/renderers/shared/fiber/ReactFiber.js b/src/renderers/shared/fiber/ReactFiber.js index 3eeba7af00..abd9face24 100644 --- a/src/renderers/shared/fiber/ReactFiber.js +++ b/src/renderers/shared/fiber/ReactFiber.js @@ -23,6 +23,8 @@ import type {TypeOfSideEffect} from 'ReactTypeOfSideEffect'; import type {PriorityLevel} from 'ReactPriorityLevel'; import type {UpdateQueue} from 'ReactFiberUpdateQueue'; +var ReactFeatureFlags = require('ReactFeatureFlags'); + var { IndeterminateComponent, ClassComponent, @@ -374,7 +376,11 @@ function createFiberFromElementType( internalContextTag: TypeOfInternalContext, debugOwner: null | Fiber | ReactInstance, ): Fiber { - if (type != null && (type: any).unstable_asyncUpdates === true) { + if ( + ReactFeatureFlags.enableAsyncSubtreeAPI && + type != null && + (type: any).unstable_asyncUpdates === true + ) { internalContextTag |= AsyncUpdates; } diff --git a/src/renderers/shared/fiber/ReactFiberReconciler.js b/src/renderers/shared/fiber/ReactFiberReconciler.js index 309ede457f..3c95e39c97 100644 --- a/src/renderers/shared/fiber/ReactFiberReconciler.js +++ b/src/renderers/shared/fiber/ReactFiberReconciler.js @@ -17,6 +17,8 @@ import type {FiberRoot} from 'ReactFiberRoot'; import type {PriorityLevel} from 'ReactPriorityLevel'; import type {ReactNodeList} from 'ReactTypes'; +var ReactFeatureFlags = require('ReactFeatureFlags'); + var { AsyncUpdates, } = require('ReactTypeOfInternalContext'); @@ -119,7 +121,6 @@ export type HostConfig = { resetAfterCommit(): void, useSyncScheduling?: boolean, - enableAsyncSubtreeAPI?: boolean, }; export type Reconciler = { @@ -189,7 +190,8 @@ module.exports = function( // Check if the top-level element is an async wrapper component. If so, treat // updates to the root as async. This is a bit weird but lets us avoid a separate // `renderAsync` API. - const forceAsync = element != null && + const forceAsync = ReactFeatureFlags.enableAsyncSubtreeAPI && + element != null && element.type != null && (element.type: any).unstable_asyncUpdates === true; const priorityLevel = getPriorityContext(current, forceAsync); diff --git a/src/renderers/shared/fiber/ReactFiberScheduler.js b/src/renderers/shared/fiber/ReactFiberScheduler.js index c2e05aefd2..fbc6ea62b5 100644 --- a/src/renderers/shared/fiber/ReactFiberScheduler.js +++ b/src/renderers/shared/fiber/ReactFiberScheduler.js @@ -169,7 +169,6 @@ module.exports = function( useSyncScheduling, prepareForCommit, resetAfterCommit, - enableAsyncSubtreeAPI, } = config; // The priority level to use when scheduling an update. We use NoWork to @@ -1353,8 +1352,7 @@ module.exports = function( if (priorityLevel === NoWork) { if ( !useSyncScheduling || - (enableAsyncSubtreeAPI === true && - fiber.internalContextTag & AsyncUpdates) || + fiber.internalContextTag & AsyncUpdates || forceAsync ) { priorityLevel = LowPriority; diff --git a/src/renderers/shared/utils/ReactFeatureFlags.js b/src/renderers/shared/utils/ReactFeatureFlags.js index ce0a442c11..60e91fb64f 100644 --- a/src/renderers/shared/utils/ReactFeatureFlags.js +++ b/src/renderers/shared/utils/ReactFeatureFlags.js @@ -19,6 +19,7 @@ var ReactFeatureFlags = { logTopLevelRenders: false, prepareNewChildrenBeforeUnmountInStack: true, disableNewFiberFeatures: false, + enableAsyncSubtreeAPI: false, }; module.exports = ReactFeatureFlags;