Remove enableAsyncSubtreeAPI from host config
Use a ReactFeatureFlag instead. It won't be per-renderer, but we likely won't need that. When enableAsyncSubtreeAPI is false, unstable_asyncUpdates is ignored, but does not warn or throw. That way if we discover a bug in async mode, we can flip the flag and revert back to sync without code changes.
This commit is contained in:
parent
0c896ffe6b
commit
9b676a7d0b
|
@ -751,11 +751,11 @@ src/renderers/dom/fiber/__tests__/ReactDOMFiber-test.js
|
||||||
|
|
||||||
src/renderers/dom/fiber/__tests__/ReactDOMFiberAsync-test.js
|
src/renderers/dom/fiber/__tests__/ReactDOMFiberAsync-test.js
|
||||||
* renders synchronously by default
|
* renders synchronously by default
|
||||||
* throws when calling async APIs when feature flag is disabled
|
* renders syncrhonously when feature flag is disabled
|
||||||
* unstable_asyncUpdates creates an async subtree
|
|
||||||
* updates inside an async subtree are async by default
|
|
||||||
* unstable_asyncUpdates at the root makes the entire tree async
|
* unstable_asyncUpdates at the root makes the entire tree async
|
||||||
* updates inside an async tree are async by default
|
* 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
|
src/renderers/dom/shared/__tests__/CSSProperty-test.js
|
||||||
* should generate browser prefixes for its `isUnitlessNumber`
|
* should generate browser prefixes for its `isUnitlessNumber`
|
||||||
|
|
|
@ -364,7 +364,6 @@ var DOMRenderer = ReactFiberReconciler({
|
||||||
scheduleDeferredCallback: ReactDOMFrameScheduling.rIC,
|
scheduleDeferredCallback: ReactDOMFrameScheduling.rIC,
|
||||||
|
|
||||||
useSyncScheduling: !ReactDOMFeatureFlags.fiberAsyncScheduling,
|
useSyncScheduling: !ReactDOMFeatureFlags.fiberAsyncScheduling,
|
||||||
enableAsyncSubtreeAPI: ReactDOMFeatureFlags.enableAsyncSubtreeAPI,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ReactGenericBatching.injection.injectFiberBatchedUpdates(
|
ReactGenericBatching.injection.injectFiberBatchedUpdates(
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
var React = require('react');
|
var React = require('react');
|
||||||
var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
|
var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
|
||||||
|
var ReactFeatureFlags = require('ReactFeatureFlags');
|
||||||
|
|
||||||
var ReactDOM;
|
var ReactDOM;
|
||||||
|
|
||||||
|
@ -23,21 +24,69 @@ describe('ReactDOMFiberAsync', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (ReactDOMFeatureFlags.useFiber) {
|
if (ReactDOMFeatureFlags.useFiber) {
|
||||||
it('throws when calling async APIs when feature flag is disabled', () => {
|
it('renders syncrhonously when feature flag is disabled', () => {
|
||||||
expect(() => {
|
function Async(props) {
|
||||||
ReactDOM.unstable_asyncRender(<div>Hi</div>, container);
|
return props.children;
|
||||||
}).toThrow('ReactDOM.unstable_asyncRender is not a function');
|
}
|
||||||
|
Async.unstable_asyncUpdates = true;
|
||||||
|
ReactDOM.render(<Async><div>Hi</div></Async>, container);
|
||||||
|
expect(container.textContent).toEqual('Hi');
|
||||||
|
|
||||||
|
ReactDOM.render(<Async><div>Bye</div></Async>, container);
|
||||||
|
expect(container.textContent).toEqual('Bye');
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('with feature flag enabled', () => {
|
describe('with feature flag enabled', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.resetModules();
|
jest.resetModules();
|
||||||
ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
|
ReactFeatureFlags = require('ReactFeatureFlags');
|
||||||
container = document.createElement('div');
|
container = document.createElement('div');
|
||||||
ReactDOMFeatureFlags.enableAsyncSubtreeAPI = true;
|
ReactFeatureFlags.enableAsyncSubtreeAPI = true;
|
||||||
ReactDOM = require('react-dom');
|
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(<Async><div>Hi</div></Async>, container);
|
||||||
|
expect(container.textContent).toEqual('');
|
||||||
|
jest.runAllTimers();
|
||||||
|
expect(container.textContent).toEqual('Hi');
|
||||||
|
|
||||||
|
ReactDOM.render(<Async><div>Bye</div></Async>, 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 <div>{this.state.step}</div>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReactDOM.render(<Async><Component /></Async>, 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', () => {
|
it('unstable_asyncUpdates creates an async subtree', () => {
|
||||||
let instance;
|
let instance;
|
||||||
class Component extends React.Component {
|
class Component extends React.Component {
|
||||||
|
@ -81,48 +130,6 @@ describe('ReactDOMFiberAsync', () => {
|
||||||
jest.runAllTimers();
|
jest.runAllTimers();
|
||||||
expect(container.textContent).toEqual('1');
|
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(<Async><div>Hi</div></Async>, container);
|
|
||||||
expect(container.textContent).toEqual('');
|
|
||||||
jest.runAllTimers();
|
|
||||||
expect(container.textContent).toEqual('Hi');
|
|
||||||
|
|
||||||
ReactDOM.render(<Async><div>Bye</div></Async>, 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 <div>{this.state.step}</div>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReactDOM.render(<Async><Component /></Async>, 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');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
|
|
||||||
var ReactDOMFeatureFlags = {
|
var ReactDOMFeatureFlags = {
|
||||||
fiberAsyncScheduling: false,
|
fiberAsyncScheduling: false,
|
||||||
enableAsyncSubtreeAPI: false,
|
|
||||||
useCreateElement: true,
|
useCreateElement: true,
|
||||||
useFiber: true,
|
useFiber: true,
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,6 +23,8 @@ import type {TypeOfSideEffect} from 'ReactTypeOfSideEffect';
|
||||||
import type {PriorityLevel} from 'ReactPriorityLevel';
|
import type {PriorityLevel} from 'ReactPriorityLevel';
|
||||||
import type {UpdateQueue} from 'ReactFiberUpdateQueue';
|
import type {UpdateQueue} from 'ReactFiberUpdateQueue';
|
||||||
|
|
||||||
|
var ReactFeatureFlags = require('ReactFeatureFlags');
|
||||||
|
|
||||||
var {
|
var {
|
||||||
IndeterminateComponent,
|
IndeterminateComponent,
|
||||||
ClassComponent,
|
ClassComponent,
|
||||||
|
@ -374,7 +376,11 @@ function createFiberFromElementType(
|
||||||
internalContextTag: TypeOfInternalContext,
|
internalContextTag: TypeOfInternalContext,
|
||||||
debugOwner: null | Fiber | ReactInstance,
|
debugOwner: null | Fiber | ReactInstance,
|
||||||
): Fiber {
|
): Fiber {
|
||||||
if (type != null && (type: any).unstable_asyncUpdates === true) {
|
if (
|
||||||
|
ReactFeatureFlags.enableAsyncSubtreeAPI &&
|
||||||
|
type != null &&
|
||||||
|
(type: any).unstable_asyncUpdates === true
|
||||||
|
) {
|
||||||
internalContextTag |= AsyncUpdates;
|
internalContextTag |= AsyncUpdates;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@ import type {FiberRoot} from 'ReactFiberRoot';
|
||||||
import type {PriorityLevel} from 'ReactPriorityLevel';
|
import type {PriorityLevel} from 'ReactPriorityLevel';
|
||||||
import type {ReactNodeList} from 'ReactTypes';
|
import type {ReactNodeList} from 'ReactTypes';
|
||||||
|
|
||||||
|
var ReactFeatureFlags = require('ReactFeatureFlags');
|
||||||
|
|
||||||
var {
|
var {
|
||||||
AsyncUpdates,
|
AsyncUpdates,
|
||||||
} = require('ReactTypeOfInternalContext');
|
} = require('ReactTypeOfInternalContext');
|
||||||
|
@ -119,7 +121,6 @@ export type HostConfig<T, P, I, TI, PI, C, CX, PL> = {
|
||||||
resetAfterCommit(): void,
|
resetAfterCommit(): void,
|
||||||
|
|
||||||
useSyncScheduling?: boolean,
|
useSyncScheduling?: boolean,
|
||||||
enableAsyncSubtreeAPI?: boolean,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Reconciler<C, I, TI> = {
|
export type Reconciler<C, I, TI> = {
|
||||||
|
@ -189,7 +190,8 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
|
||||||
// Check if the top-level element is an async wrapper component. If so, treat
|
// 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
|
// updates to the root as async. This is a bit weird but lets us avoid a separate
|
||||||
// `renderAsync` API.
|
// `renderAsync` API.
|
||||||
const forceAsync = element != null &&
|
const forceAsync = ReactFeatureFlags.enableAsyncSubtreeAPI &&
|
||||||
|
element != null &&
|
||||||
element.type != null &&
|
element.type != null &&
|
||||||
(element.type: any).unstable_asyncUpdates === true;
|
(element.type: any).unstable_asyncUpdates === true;
|
||||||
const priorityLevel = getPriorityContext(current, forceAsync);
|
const priorityLevel = getPriorityContext(current, forceAsync);
|
||||||
|
|
|
@ -169,7 +169,6 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
|
||||||
useSyncScheduling,
|
useSyncScheduling,
|
||||||
prepareForCommit,
|
prepareForCommit,
|
||||||
resetAfterCommit,
|
resetAfterCommit,
|
||||||
enableAsyncSubtreeAPI,
|
|
||||||
} = config;
|
} = config;
|
||||||
|
|
||||||
// The priority level to use when scheduling an update. We use NoWork to
|
// The priority level to use when scheduling an update. We use NoWork to
|
||||||
|
@ -1353,8 +1352,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
|
||||||
if (priorityLevel === NoWork) {
|
if (priorityLevel === NoWork) {
|
||||||
if (
|
if (
|
||||||
!useSyncScheduling ||
|
!useSyncScheduling ||
|
||||||
(enableAsyncSubtreeAPI === true &&
|
fiber.internalContextTag & AsyncUpdates ||
|
||||||
fiber.internalContextTag & AsyncUpdates) ||
|
|
||||||
forceAsync
|
forceAsync
|
||||||
) {
|
) {
|
||||||
priorityLevel = LowPriority;
|
priorityLevel = LowPriority;
|
||||||
|
|
|
@ -19,6 +19,7 @@ var ReactFeatureFlags = {
|
||||||
logTopLevelRenders: false,
|
logTopLevelRenders: false,
|
||||||
prepareNewChildrenBeforeUnmountInStack: true,
|
prepareNewChildrenBeforeUnmountInStack: true,
|
||||||
disableNewFiberFeatures: false,
|
disableNewFiberFeatures: false,
|
||||||
|
enableAsyncSubtreeAPI: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = ReactFeatureFlags;
|
module.exports = ReactFeatureFlags;
|
||||||
|
|
Loading…
Reference in New Issue