Skip to content

Commit

Permalink
Replace unstable_AsyncComponent with Unstable_AsyncMode
Browse files Browse the repository at this point in the history
Mirrors the StrictMode API and uses the new Mode type of work.
  • Loading branch information
acdlite committed Jan 30, 2018
1 parent a7b9f98 commit 3757ab6
Show file tree
Hide file tree
Showing 16 changed files with 91 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ let ReactFeatureFlags = require('shared/ReactFeatureFlags');

let ReactDOM;

const AsyncComponent = React.unstable_AsyncComponent;
const AsyncMode = React.Unstable_AsyncMode;

describe('ReactDOMFiberAsync', () => {
let container;
Expand All @@ -40,23 +40,22 @@ describe('ReactDOMFiberAsync', () => {
jest.resetModules();
ReactFeatureFlags = require('shared/ReactFeatureFlags');
container = document.createElement('div');
ReactFeatureFlags.enableAsyncSubtreeAPI = false;
ReactDOM = require('react-dom');
});

it('renders synchronously', () => {
ReactDOM.render(
<AsyncComponent>
<AsyncMode>
<div>Hi</div>
</AsyncComponent>,
</AsyncMode>,
container,
);
expect(container.textContent).toEqual('Hi');

ReactDOM.render(
<AsyncComponent>
<AsyncMode>
<div>Bye</div>
</AsyncComponent>,
</AsyncMode>,
container,
);
expect(container.textContent).toEqual('Bye');
Expand All @@ -68,7 +67,6 @@ describe('ReactDOMFiberAsync', () => {
jest.resetModules();
ReactFeatureFlags = require('shared/ReactFeatureFlags');
container = document.createElement('div');
ReactFeatureFlags.enableAsyncSubtreeAPI = true;
ReactFeatureFlags.enableCreateRoot = true;
ReactDOM = require('react-dom');
});
Expand Down Expand Up @@ -108,9 +106,9 @@ describe('ReactDOMFiberAsync', () => {
expect(container.textContent).toEqual('1');
});

it('AsyncComponent creates an async subtree', () => {
it('AsyncMode creates an async subtree', () => {
let instance;
class Component extends React.unstable_AsyncComponent {
class Component extends React.Component {
state = {step: 0};
render() {
instance = this;
Expand All @@ -119,9 +117,9 @@ describe('ReactDOMFiberAsync', () => {
}

ReactDOM.render(
<div>
<AsyncMode>
<Component />
</div>,
</AsyncMode>,
container,
);
jest.runAllTimers();
Expand All @@ -133,12 +131,6 @@ describe('ReactDOMFiberAsync', () => {
});

it('updates inside an async subtree are async by default', () => {
class Component extends React.unstable_AsyncComponent {
render() {
return <Child />;
}
}

let instance;
class Child extends React.Component {
state = {step: 0};
Expand All @@ -150,7 +142,9 @@ describe('ReactDOMFiberAsync', () => {

ReactDOM.render(
<div>
<Component />
<AsyncMode>
<Child />
</AsyncMode>
</div>,
container,
);
Expand Down Expand Up @@ -264,7 +258,7 @@ describe('ReactDOMFiberAsync', () => {
let ops = [];
let instance;

class Component extends React.unstable_AsyncComponent {
class Component extends React.Component {
state = {text: ''};
push(val) {
this.setState(state => ({text: state.text + val}));
Expand All @@ -278,7 +272,12 @@ describe('ReactDOMFiberAsync', () => {
}
}

ReactDOM.render(<Component />, container);
ReactDOM.render(
<AsyncMode>
<Component />
</AsyncMode>,
container,
);
jest.runAllTimers();

// Updates are async by default
Expand Down
14 changes: 7 additions & 7 deletions packages/react-dom/src/__tests__/ReactDOMRoot-test.internal.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
let React = require('react');
let ReactDOM = require('react-dom');
let ReactDOMServer = require('react-dom/server');
let AsyncComponent = React.unstable_AsyncComponent;
let AsyncMode = React.Unstable_AsyncMode;

describe('ReactDOMRoot', () => {
let container;
Expand Down Expand Up @@ -70,7 +70,7 @@ describe('ReactDOMRoot', () => {
React = require('react');
ReactDOM = require('react-dom');
ReactDOMServer = require('react-dom/server');
AsyncComponent = React.unstable_AsyncComponent;
AsyncMode = React.Unstable_AsyncMode;
});

it('renders children', () => {
Expand All @@ -92,7 +92,7 @@ describe('ReactDOMRoot', () => {

it('`root.render` returns a thenable work object', () => {
const root = ReactDOM.createRoot(container);
const work = root.render(<AsyncComponent>Hi</AsyncComponent>);
const work = root.render(<AsyncMode>Hi</AsyncMode>);
let ops = [];
work.then(() => {
ops.push('inside callback: ' + container.textContent);
Expand All @@ -110,7 +110,7 @@ describe('ReactDOMRoot', () => {

it('resolves `work.then` callback synchronously if the work already committed', () => {
const root = ReactDOM.createRoot(container);
const work = root.render(<AsyncComponent>Hi</AsyncComponent>);
const work = root.render(<AsyncMode>Hi</AsyncMode>);
flush();
let ops = [];
work.then(() => {
Expand Down Expand Up @@ -209,10 +209,10 @@ describe('ReactDOMRoot', () => {
});

it('can wait for a batch to finish', () => {
const Async = React.unstable_AsyncComponent;
const AsyncMode = React.Unstable_AsyncMode;
const root = ReactDOM.createRoot(container);
const batch = root.createBatch();
batch.render(<Async>Foo</Async>);
batch.render(<AsyncMode>Foo</AsyncMode>);

flush();

Expand Down Expand Up @@ -252,7 +252,7 @@ describe('ReactDOMRoot', () => {

it('can commit an empty batch', () => {
const root = ReactDOM.createRoot(container);
root.render(<AsyncComponent>1</AsyncComponent>);
root.render(<AsyncMode>1</AsyncMode>);

expire(2000);
// This batch has a later expiration time than the earlier update.
Expand Down
15 changes: 8 additions & 7 deletions packages/react-reconciler/src/ReactFiber.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,15 @@ import {
import getComponentName from 'shared/getComponentName';

import {NoWork} from './ReactFiberExpirationTime';
import {
NoContext,
AsyncUpdates,
StrictMode,
} from './ReactTypeOfInternalContext';
import {NoContext, AsyncMode, StrictMode} from './ReactTypeOfInternalContext';
import {
REACT_FRAGMENT_TYPE,
REACT_RETURN_TYPE,
REACT_CALL_TYPE,
REACT_STRICT_MODE_TYPE,
REACT_PROVIDER_TYPE,
REACT_CONTEXT_TYPE,
REACT_ASYNC_MODE_TYPE,
} from 'shared/ReactSymbols';

let hasBadMapPolyfill;
Expand Down Expand Up @@ -123,7 +120,7 @@ export type Fiber = {|
memoizedState: any,

// Bitfield that describes properties about the fiber and its subtree. E.g.
// the AsyncUpdates flag indicates whether the subtree should be async-by-
// the AsyncMode flag indicates whether the subtree should be async-by-
// default. When a fiber is created, it inherits the internalContextTag of its
// parent. Additional flags can be set at creation time, but after than the
// value should remain unchanged throughout the fiber's lifetime, particularly
Expand Down Expand Up @@ -303,7 +300,7 @@ export function createWorkInProgress(
}

export function createHostRootFiber(isAsync): Fiber {
const internalContextTag = isAsync ? AsyncUpdates | StrictMode : NoContext;
const internalContextTag = isAsync ? AsyncMode | StrictMode : NoContext;
return createFiber(HostRoot, null, null, internalContextTag);
}

Expand Down Expand Up @@ -336,6 +333,10 @@ export function createFiberFromElement(
expirationTime,
key,
);
case REACT_ASYNC_MODE_TYPE:
fiberTag = Mode;
internalContextTag |= AsyncMode | StrictMode;
break;
case REACT_STRICT_MODE_TYPE:
fiberTag = Mode;
internalContextTag |= StrictMode;
Expand Down
4 changes: 2 additions & 2 deletions packages/react-reconciler/src/ReactFiberBeginWork.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ import {
} from './ReactFiberContext';
import {pushProvider} from './ReactFiberNewContext';
import {NoWork, Never} from './ReactFiberExpirationTime';
import {AsyncUpdates, StrictMode} from './ReactTypeOfInternalContext';
import {AsyncMode, StrictMode} from './ReactTypeOfInternalContext';
import MAX_SIGNED_31_BIT_INT from './maxSigned31BitInt';

let didWarnAboutBadClass;
Expand Down Expand Up @@ -438,7 +438,7 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
// Check the host config to see if the children are offscreen/hidden.
if (
renderExpirationTime !== Never &&
workInProgress.internalContextTag & AsyncUpdates &&
workInProgress.internalContextTag & AsyncMode &&
shouldDeprioritizeSubtree(type, nextProps)
) {
// Down-prioritize the children.
Expand Down
10 changes: 1 addition & 9 deletions packages/react-reconciler/src/ReactFiberClassComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {Update} from 'shared/ReactTypeOfSideEffect';
import {
debugRenderPhaseSideEffects,
debugRenderPhaseSideEffectsForStrictMode,
enableAsyncSubtreeAPI,
warnAboutDeprecatedLifecycles,
} from 'shared/ReactFeatureFlags';
import ReactStrictModeWarnings from './ReactStrictModeWarnings';
Expand All @@ -27,7 +26,7 @@ import invariant from 'fbjs/lib/invariant';
import warning from 'fbjs/lib/warning';

import {startPhaseTimer, stopPhaseTimer} from './ReactDebugFiberPerf';
import {AsyncUpdates, StrictMode} from './ReactTypeOfInternalContext';
import {StrictMode} from './ReactTypeOfInternalContext';
import {
cacheContext,
getMaskedContext,
Expand Down Expand Up @@ -605,13 +604,6 @@ export default function(

if (workInProgress.type != null && workInProgress.type.prototype != null) {
const prototype = workInProgress.type.prototype;

if (enableAsyncSubtreeAPI) {
if (prototype.unstable_isAsyncReactComponent === true) {
workInProgress.internalContextTag |= AsyncUpdates;
workInProgress.internalContextTag |= StrictMode;
}
}
}

if (__DEV__) {
Expand Down
4 changes: 2 additions & 2 deletions packages/react-reconciler/src/ReactFiberScheduler.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ import {
expirationTimeToMs,
computeExpirationBucket,
} from './ReactFiberExpirationTime';
import {AsyncUpdates} from './ReactTypeOfInternalContext';
import {AsyncMode} from './ReactTypeOfInternalContext';
import {getUpdateExpirationTime} from './ReactFiberUpdateQueue';
import {resetContext as resetLegacyContext} from './ReactFiberContext';
import {resetProviderStack} from './ReactFiberNewContext';
Expand Down Expand Up @@ -1200,7 +1200,7 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
} else {
// No explicit expiration context was set, and we're not currently
// performing work. Calculate a new expiration time.
if (fiber.internalContextTag & AsyncUpdates) {
if (fiber.internalContextTag & AsyncMode) {
// This is an async update
expirationTime = computeAsyncExpiration();
} else {
Expand Down
6 changes: 3 additions & 3 deletions packages/react-reconciler/src/ReactTypeOfInternalContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@

export type TypeOfInternalContext = number;

export const NoContext = 0b00000000;
export const AsyncUpdates = 0b00000001;
export const StrictMode = 0b00000010;
export const NoContext = 0b00;
export const AsyncMode = 0b01;
export const StrictMode = 0b10;
10 changes: 7 additions & 3 deletions packages/react/src/React.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@

import assign from 'object-assign';
import ReactVersion from 'shared/ReactVersion';
import {REACT_FRAGMENT_TYPE, REACT_STRICT_MODE_TYPE} from 'shared/ReactSymbols';
import {
REACT_FRAGMENT_TYPE,
REACT_STRICT_MODE_TYPE,
REACT_ASYNC_MODE_TYPE,
} from 'shared/ReactSymbols';

import {AsyncComponent, Component, PureComponent} from './ReactBaseClasses';
import {Component, PureComponent} from './ReactBaseClasses';
import {forEach, map, count, toArray, only} from './ReactChildren';
import ReactCurrentOwner from './ReactCurrentOwner';
import {
Expand Down Expand Up @@ -38,10 +42,10 @@ const React = {

Component,
PureComponent,
unstable_AsyncComponent: AsyncComponent,

Fragment: REACT_FRAGMENT_TYPE,
StrictMode: REACT_STRICT_MODE_TYPE,
Unstable_AsyncMode: REACT_ASYNC_MODE_TYPE,

createElement: __DEV__ ? createElementWithValidation : createElement,
cloneElement: __DEV__ ? cloneElementWithValidation : cloneElement,
Expand Down
21 changes: 1 addition & 20 deletions packages/react/src/ReactBaseClasses.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,23 +136,4 @@ pureComponentPrototype.constructor = PureComponent;
Object.assign(pureComponentPrototype, Component.prototype);
pureComponentPrototype.isPureReactComponent = true;

/**
* Special component type that opts subtree into async rendering mode.
*/
function AsyncComponent(props, context, updater) {
this.props = props;
this.context = context;
this.refs = emptyObject;
this.updater = updater || ReactNoopUpdateQueue;
}

const asyncComponentPrototype = (AsyncComponent.prototype = new ComponentDummy());
asyncComponentPrototype.constructor = AsyncComponent;
// Avoid an extra prototype jump for these methods.
Object.assign(asyncComponentPrototype, Component.prototype);
asyncComponentPrototype.unstable_isAsyncReactComponent = true;
asyncComponentPrototype.render = function() {
return this.props.children;
};

export {AsyncComponent, Component, PureComponent};
export {Component, PureComponent};
2 changes: 2 additions & 0 deletions packages/react/src/ReactElementValidator.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
getIteratorFn,
REACT_FRAGMENT_TYPE,
REACT_STRICT_MODE_TYPE,
REACT_ASYNC_MODE_TYPE,
} from 'shared/ReactSymbols';
import checkPropTypes from 'prop-types/checkPropTypes';
import warning from 'fbjs/lib/warning';
Expand Down Expand Up @@ -287,6 +288,7 @@ export function createElementWithValidation(type, props, children) {
typeof type === 'function' ||
// Note: its typeof might be other than 'symbol' or 'number' if it's a polyfill.
type === REACT_FRAGMENT_TYPE ||
type === REACT_ASYNC_MODE_TYPE ||
type === REACT_STRICT_MODE_TYPE;

// We warn in this case but don't throw. We expect the element creation to
Expand Down
Loading

0 comments on commit 3757ab6

Please sign in to comment.