Sync React 16 from alpha 6 to 12

Reviewed By: spicyj

Differential Revision: D4926070

fbshipit-source-id: c23c79ccd53eb594447d9b47fe3ac6e82499bd42
This commit is contained in:
Brian Vaughn 2017-05-03 17:09:36 -07:00 коммит произвёл Facebook Github Bot
Родитель cc3d034460
Коммит ef0bd5c71d
86 изменённых файлов: 1540 добавлений и 765 удалений

Просмотреть файл

@ -11,7 +11,7 @@
'use strict';
var PooledClass = require('react/lib/PooledClass');
var PooledClass = require('PooledClass');
var twoArgumentPooler = PooledClass.twoArgumentPooler;

Просмотреть файл

@ -11,7 +11,7 @@
'use strict';
var PooledClass = require('react/lib/PooledClass');
var PooledClass = require('PooledClass');
var twoArgumentPooler = PooledClass.twoArgumentPooler;

Просмотреть файл

@ -15,7 +15,6 @@ var ImageResizeMode = require('ImageResizeMode');
var ImageStylePropTypes = require('ImageStylePropTypes');
var NativeMethodsMixin = require('NativeMethodsMixin');
var NativeModules = require('NativeModules');
var PropTypes = require('react/lib/ReactPropTypes');
var React = require('React');
var PropTypes = require('prop-types');
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');

Просмотреть файл

@ -32,28 +32,32 @@ let _asyncCookie = 0;
const ReactSystraceDevtool = __DEV__ ? {
onBeforeMountComponent(debugID) {
const displayName = require('react/lib/ReactComponentTreeHook').getDisplayName(debugID);
const ReactComponentTreeHook = require('ReactGlobalSharedState').ReactComponentTreeHook;
const displayName = ReactComponentTreeHook.getDisplayName(debugID);
Systrace.beginEvent(`ReactReconciler.mountComponent(${displayName})`);
},
onMountComponent(debugID) {
Systrace.endEvent();
},
onBeforeUpdateComponent(debugID) {
const displayName = require('react/lib/ReactComponentTreeHook').getDisplayName(debugID);
const ReactComponentTreeHook = require('ReactGlobalSharedState').ReactComponentTreeHook;
const displayName = ReactComponentTreeHook.getDisplayName(debugID);
Systrace.beginEvent(`ReactReconciler.updateComponent(${displayName})`);
},
onUpdateComponent(debugID) {
Systrace.endEvent();
},
onBeforeUnmountComponent(debugID) {
const displayName = require('react/lib/ReactComponentTreeHook').getDisplayName(debugID);
const ReactComponentTreeHook = require('ReactGlobalSharedState').ReactComponentTreeHook;
const displayName = ReactComponentTreeHook.getDisplayName(debugID);
Systrace.beginEvent(`ReactReconciler.unmountComponent(${displayName})`);
},
onUnmountComponent(debugID) {
Systrace.endEvent();
},
onBeginLifeCycleTimer(debugID, timerType) {
const displayName = require('react/lib/ReactComponentTreeHook').getDisplayName(debugID);
const ReactComponentTreeHook = require('ReactGlobalSharedState').ReactComponentTreeHook;
const displayName = ReactComponentTreeHook.getDisplayName(debugID);
Systrace.beginEvent(`${displayName}.${timerType}()`);
},
onEndLifeCycleTimer(debugID, timerType) {

Просмотреть файл

@ -11,4 +11,4 @@
'use strict';
module.exports = '16.0.0-alpha.6';
module.exports = '16.0.0-alpha.12';

Просмотреть файл

@ -99,7 +99,7 @@ var NativeMethodsMixin = {
},
/**
* Like [`measure()`](#measure), but measures the view relative to an ancestor,
* Like [`measure()`](#measure), but measures the view relative an ancestor,
* specified as `relativeToNativeNode`. This means that the returned x, y
* are relative to the origin x, y of the ancestor view.
*
@ -176,7 +176,8 @@ function setNativePropsFiber(componentOrHandle: any, nativeProps: Object) {
return;
}
const viewConfig: ReactNativeBaseComponentViewConfig = maybeInstance.viewConfig;
const viewConfig: ReactNativeBaseComponentViewConfig =
maybeInstance.viewConfig;
if (__DEV__) {
warnForStyleProps(nativeProps, viewConfig.validAttributes);

Просмотреть файл

@ -71,12 +71,14 @@ function throwOnStylesProp(component: any, props: any) {
if (props.styles !== undefined) {
var owner = component._owner || null;
var name = component.constructor.displayName;
var msg = '`styles` is not a supported property of `' +
var msg =
'`styles` is not a supported property of `' +
name +
'`, did ' +
'you mean `style` (singular)?';
if (owner && owner.constructor && owner.constructor.displayName) {
msg += '\n\nCheck the `' +
msg +=
'\n\nCheck the `' +
owner.constructor.displayName +
'` parent ' +
' component.';

Просмотреть файл

@ -377,7 +377,8 @@ function diffProperties(
typeof attributeConfig.process === 'function'
) {
// case: CustomAttributeConfiguration
var shouldUpdate = prevProp === undefined ||
var shouldUpdate =
prevProp === undefined ||
(typeof attributeConfig.diff === 'function'
? attributeConfig.diff(prevProp, nextProp)
: defaultDiffer(prevProp, nextProp));

Просмотреть файл

@ -9,6 +9,7 @@
* @providesModule ReactNativeBaseComponent
* @flow
*/
'use strict';
var NativeMethodsMixin = require('NativeMethodsMixin');

Просмотреть файл

@ -23,9 +23,8 @@ var customDirectEventTypes = UIManager.customDirectEventTypes;
var allTypesByEventName = {};
for (var bubblingTypeName in customBubblingEventTypes) {
allTypesByEventName[bubblingTypeName] = customBubblingEventTypes[
bubblingTypeName
];
allTypesByEventName[bubblingTypeName] =
customBubblingEventTypes[bubblingTypeName];
}
for (var directTypeName in customDirectEventTypes) {

Просмотреть файл

@ -23,6 +23,7 @@ const ReactNativeInjection = require('ReactNativeInjection');
const ReactNativeTagHandles = require('ReactNativeTagHandles');
const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry');
const ReactPortal = require('ReactPortal');
const ReactVersion = require('ReactVersion');
const UIManager = require('UIManager');
const deepFreezeAndThrowOnMutationInDev = require('deepFreezeAndThrowOnMutationInDev');
@ -239,9 +240,9 @@ const NativeRenderer = ReactFiberReconciler({
// Either way we need to pass a copy of the Array to prevent it from being frozen.
const nativeTags = parentInstance._children.map(
child =>
typeof child === 'number'
(typeof child === 'number'
? child // Leaf node (eg text)
: child._nativeTag,
: child._nativeTag),
);
UIManager.setChildren(
@ -396,7 +397,8 @@ ReactGenericBatching.injection.injectFiberBatchedUpdates(
const roots = new Map();
findNodeHandle.injection.injectFindNode((fiber: Fiber) =>
NativeRenderer.findHostInstance(fiber));
NativeRenderer.findHostInstance(fiber),
);
findNodeHandle.injection.injectFindRootNodeID(instance => instance);
// Intercept lifecycle errors and ensure they are shown with the correct stack
@ -463,6 +465,9 @@ if (typeof injectInternals === 'function') {
injectInternals({
findFiberByHostInstance: ReactNativeComponentTree.getClosestInstanceFromNode,
findHostInstanceByFiber: NativeRenderer.findHostInstance,
// This is an enum because we may add more (e.g. profiler build)
bundleType: __DEV__ ? 1 : 0,
version: ReactVersion,
});
}

Просмотреть файл

@ -17,10 +17,7 @@ var ReactNativeAttributePayload = require('ReactNativeAttributePayload');
var TextInputState = require('TextInputState');
var UIManager = require('UIManager');
var {
mountSafeCallback,
warnForStyleProps,
} = require('NativeMethodsMixinUtils');
var {mountSafeCallback, warnForStyleProps} = require('NativeMethodsMixinUtils');
import type {
MeasureInWindowOnSuccessCallback,

Просмотреть файл

@ -11,6 +11,7 @@
'use strict';
var PropTypes;
var RCTEventEmitter;
var React;
var ReactNative;
@ -21,6 +22,7 @@ var createReactNativeComponentClass;
beforeEach(() => {
jest.resetModules();
PropTypes = require('prop-types');
RCTEventEmitter = require('RCTEventEmitter');
React = require('react');
ReactNative = require('ReactNative');
@ -56,6 +58,7 @@ it('handles events', () => {
1,
);
expect(UIManager.__dumpHierarchyForJestTestsOnly()).toMatchSnapshot();
expect(UIManager.createView.mock.calls.length).toBe(2);
// Don't depend on the order of createView() calls.

Просмотреть файл

@ -69,7 +69,7 @@ describe('ReactNative', () => {
var a;
var b;
var c = ReactNative.render(
<View foo="foo" ref={v => a = v} />,
<View foo="foo" ref={v => (a = v)} />,
11,
function() {
b = this;
@ -80,4 +80,32 @@ describe('ReactNative', () => {
expect(a).toBe(b);
expect(a).toBe(c);
});
it('renders and reorders children', () => {
var View = createReactNativeComponentClass({
validAttributes: {title: true},
uiViewClassName: 'View',
});
class Component extends React.Component {
render() {
var chars = this.props.chars.split('');
return (
<View>
{chars.map(text => <View key={text} title={text} />)}
</View>
);
}
}
// Mini multi-child stress test: lots of reorders, some adds, some removes.
var before = 'abcdefghijklmnopqrst';
var after = 'mxhpgwfralkeoivcstzy';
ReactNative.render(<Component chars={before} />, 11);
expect(UIManager.__dumpHierarchyForJestTestsOnly()).toMatchSnapshot();
ReactNative.render(<Component chars={after} />, 11);
expect(UIManager.__dumpHierarchyForJestTestsOnly()).toMatchSnapshot();
});
});

Просмотреть файл

@ -0,0 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`handles events 1`] = `
"<native root> {}
View {\\"foo\\":\\"outer\\"}
View {\\"foo\\":\\"inner\\"}"
`;

Просмотреть файл

@ -0,0 +1,51 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`ReactNative renders and reorders children 1`] = `
"<native root> {}
View null
View {\\"title\\":\\"a\\"}
View {\\"title\\":\\"b\\"}
View {\\"title\\":\\"c\\"}
View {\\"title\\":\\"d\\"}
View {\\"title\\":\\"e\\"}
View {\\"title\\":\\"f\\"}
View {\\"title\\":\\"g\\"}
View {\\"title\\":\\"h\\"}
View {\\"title\\":\\"i\\"}
View {\\"title\\":\\"j\\"}
View {\\"title\\":\\"k\\"}
View {\\"title\\":\\"l\\"}
View {\\"title\\":\\"m\\"}
View {\\"title\\":\\"n\\"}
View {\\"title\\":\\"o\\"}
View {\\"title\\":\\"p\\"}
View {\\"title\\":\\"q\\"}
View {\\"title\\":\\"r\\"}
View {\\"title\\":\\"s\\"}
View {\\"title\\":\\"t\\"}"
`;
exports[`ReactNative renders and reorders children 2`] = `
"<native root> {}
View null
View {\\"title\\":\\"m\\"}
View {\\"title\\":\\"x\\"}
View {\\"title\\":\\"h\\"}
View {\\"title\\":\\"p\\"}
View {\\"title\\":\\"g\\"}
View {\\"title\\":\\"w\\"}
View {\\"title\\":\\"f\\"}
View {\\"title\\":\\"r\\"}
View {\\"title\\":\\"a\\"}
View {\\"title\\":\\"l\\"}
View {\\"title\\":\\"k\\"}
View {\\"title\\":\\"e\\"}
View {\\"title\\":\\"o\\"}
View {\\"title\\":\\"i\\"}
View {\\"title\\":\\"v\\"}
View {\\"title\\":\\"c\\"}
View {\\"title\\":\\"s\\"}
View {\\"title\\":\\"t\\"}
View {\\"title\\":\\"z\\"}
View {\\"title\\":\\"y\\"}"
`;

Просмотреть файл

@ -12,8 +12,8 @@
'use strict';
var ReactCurrentOwner = require('react/lib/ReactCurrentOwner');
var ReactInstanceMap = require('ReactInstanceMap');
var {ReactCurrentOwner} = require('ReactGlobalSharedState');
var invariant = require('fbjs/lib/invariant');
var warning = require('fbjs/lib/warning');

Просмотреть файл

@ -33,23 +33,22 @@ import type {Element} from 'React';
* Returns a Promise.
* @platform ios
*/
module.exports = async function takeSnapshot(
view ?: 'window' | Element<any> | number,
options ?: {
width ?: number,
height ?: number,
format ?: 'png' | 'jpeg',
quality ?: number,
function takeSnapshot(
view?: 'window' | Element<any> | number,
options?: {
width?: number,
height?: number,
format?: 'png' | 'jpeg',
quality?: number,
},
) {
if (
typeof view !== 'number' &&
view !== 'window'
) {
): Promise<any> {
if (typeof view !== 'number' && view !== 'window') {
view = ReactNative.findNodeHandle(view) || 'window';
}
// Call the hidden '__takeSnapshot' method; the main one throws an error to
// prevent accidental backwards-incompatible usage.
return UIManager.__takeSnapshot(view, options);
};
}
module.exports = takeSnapshot;

Просмотреть файл

@ -22,6 +22,7 @@
import type { Fiber } from 'ReactFiber';
import type { UpdateQueue } from 'ReactFiberUpdateQueue';
var ReactFiberInstrumentation = require('ReactFiberInstrumentation');
var ReactFiberReconciler = require('ReactFiberReconciler');
var ReactInstanceMap = require('ReactInstanceMap');
var {
@ -380,6 +381,11 @@ var ReactNoop = {
}
},
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: {
// Private. Used only by fixtures/fiber-debugger.
// (To be fair, it's the only place where `react-noop-renderer` package is used at all.)
ReactFiberInstrumentation,
},
};
module.exports = ReactNoop;

Просмотреть файл

@ -0,0 +1,170 @@
/**
* Copyright 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactDOMFrameScheduling
* @flow
*/
'use strict';
// This a built-in polyfill for requestIdleCallback. It works by scheduling
// a requestAnimationFrame, store the time for the start of the frame, then
// schedule a postMessage which gets scheduled after paint. Within the
// postMessage handler do as much work as possible until time + frame rate.
// By separating the idle call into a separate event tick we ensure that
// layout, paint and other browser work is counted against the available time.
// The frame rate is dynamically adjusted.
import type {Deadline} from 'ReactFiberReconciler';
var invariant = require('fbjs/lib/invariant');
var ExecutionEnvironment = require('fbjs/lib/ExecutionEnvironment');
// TODO: There's no way to cancel these, because Fiber doesn't atm.
let rAF: (callback: (time: number) => void) => number;
let rIC: (callback: (deadline: Deadline) => void) => number;
if (!ExecutionEnvironment.canUseDOM) {
rAF = function(frameCallback: (time: number) => void): number {
setTimeout(frameCallback, 16);
return 0;
};
rIC = function(frameCallback: (deadline: Deadline) => void): number {
setTimeout(() => {
frameCallback({
timeRemaining() {
return Infinity;
},
});
});
return 0;
};
} else if (typeof requestAnimationFrame !== 'function') {
invariant(
false,
'React depends on requestAnimationFrame. Make sure that you load a ' +
'polyfill in older browsers.',
);
} else if (typeof requestIdleCallback !== 'function') {
// Wrap requestAnimationFrame and polyfill requestIdleCallback.
var scheduledRAFCallback = null;
var scheduledRICCallback = null;
var isIdleScheduled = false;
var isAnimationFrameScheduled = false;
var frameDeadline = 0;
// We start out assuming that we run at 30fps but then the heuristic tracking
// will adjust this value to a faster fps if we get more frequent animation
// frames.
var previousFrameTime = 33;
var activeFrameTime = 33;
var frameDeadlineObject = {
timeRemaining: typeof performance === 'object' &&
typeof performance.now === 'function'
? function() {
// We assume that if we have a performance timer that the rAF callback
// gets a performance timer value. Not sure if this is always true.
return frameDeadline - performance.now();
}
: function() {
// As a fallback we use Date.now.
return frameDeadline - Date.now();
},
};
// We use the postMessage trick to defer idle work until after the repaint.
var messageKey = '__reactIdleCallback$' + Math.random().toString(36).slice(2);
var idleTick = function(event) {
if (event.source !== window || event.data !== messageKey) {
return;
}
isIdleScheduled = false;
var callback = scheduledRICCallback;
scheduledRICCallback = null;
if (callback) {
callback(frameDeadlineObject);
}
};
// Assumes that we have addEventListener in this environment. Might need
// something better for old IE.
window.addEventListener('message', idleTick, false);
var animationTick = function(rafTime) {
isAnimationFrameScheduled = false;
var nextFrameTime = rafTime - frameDeadline + activeFrameTime;
if (
nextFrameTime < activeFrameTime &&
previousFrameTime < activeFrameTime
) {
if (nextFrameTime < 8) {
// Defensive coding. We don't support higher frame rates than 120hz.
// If we get lower than that, it is probably a bug.
nextFrameTime = 8;
}
// If one frame goes long, then the next one can be short to catch up.
// If two frames are short in a row, then that's an indication that we
// actually have a higher frame rate than what we're currently optimizing.
// We adjust our heuristic dynamically accordingly. For example, if we're
// running on 120hz display or 90hz VR display.
// Take the max of the two in case one of them was an anomaly due to
// missed frame deadlines.
activeFrameTime = nextFrameTime < previousFrameTime
? previousFrameTime
: nextFrameTime;
} else {
previousFrameTime = nextFrameTime;
}
frameDeadline = rafTime + activeFrameTime;
if (!isIdleScheduled) {
isIdleScheduled = true;
window.postMessage(messageKey, '*');
}
var callback = scheduledRAFCallback;
scheduledRAFCallback = null;
if (callback) {
callback(rafTime);
}
};
rAF = function(callback: (time: number) => void): number {
// This assumes that we only schedule one callback at a time because that's
// how Fiber uses it.
scheduledRAFCallback = callback;
if (!isAnimationFrameScheduled) {
// If rIC didn't already schedule one, we need to schedule a frame.
isAnimationFrameScheduled = true;
requestAnimationFrame(animationTick);
}
return 0;
};
rIC = function(callback: (deadline: Deadline) => void): number {
// This assumes that we only schedule one callback at a time because that's
// how Fiber uses it.
scheduledRICCallback = callback;
if (!isAnimationFrameScheduled) {
// If rAF didn't already schedule one, we need to schedule a frame.
// TODO: If this rAF doesn't materialize because the browser throttles, we
// might want to still have setTimeout trigger rIC as a backup to ensure
// that we keep performing work.
isAnimationFrameScheduled = true;
requestAnimationFrame(animationTick);
}
return 0;
};
} else {
rAF = requestAnimationFrame;
rIC = requestIdleCallback;
}
exports.rAF = rAF;
exports.rIC = rIC;

Просмотреть файл

@ -14,8 +14,8 @@
var ReactInvalidSetStateWarningHook = require('ReactInvalidSetStateWarningHook');
var ReactHostOperationHistoryHook = require('ReactHostOperationHistoryHook');
var ReactComponentTreeHook = require('react/lib/ReactComponentTreeHook');
var ExecutionEnvironment = require('fbjs/lib/ExecutionEnvironment');
var {ReactComponentTreeHook} = require('ReactGlobalSharedState');
var performanceNow = require('fbjs/lib/performanceNow');
var warning = require('fbjs/lib/warning');
@ -113,25 +113,22 @@ if (__DEV__) {
};
const getTreeSnapshot = function(registeredIDs) {
return registeredIDs.reduce(
(tree, id) => {
var ownerID = ReactComponentTreeHook.getOwnerID(id);
var parentID = ReactComponentTreeHook.getParentID(id);
tree[id] = {
displayName: ReactComponentTreeHook.getDisplayName(id),
text: ReactComponentTreeHook.getText(id),
updateCount: ReactComponentTreeHook.getUpdateCount(id),
childIDs: ReactComponentTreeHook.getChildIDs(id),
// Text nodes don't have owners but this is close enough.
ownerID: ownerID ||
(parentID && ReactComponentTreeHook.getOwnerID(parentID)) ||
0,
parentID,
};
return tree;
},
{},
);
return registeredIDs.reduce((tree, id) => {
var ownerID = ReactComponentTreeHook.getOwnerID(id);
var parentID = ReactComponentTreeHook.getParentID(id);
tree[id] = {
displayName: ReactComponentTreeHook.getDisplayName(id),
text: ReactComponentTreeHook.getText(id),
updateCount: ReactComponentTreeHook.getUpdateCount(id),
childIDs: ReactComponentTreeHook.getChildIDs(id),
// Text nodes don't have owners but this is close enough.
ownerID: ownerID ||
(parentID && ReactComponentTreeHook.getOwnerID(parentID)) ||
0,
parentID,
};
return tree;
}, {});
};
const resetMeasurements = function() {
@ -252,7 +249,8 @@ if (__DEV__) {
};
var lastMarkTimeStamp = 0;
var canUsePerformanceMeasure: boolean = typeof performance !== 'undefined' &&
var canUsePerformanceMeasure: boolean =
typeof performance !== 'undefined' &&
typeof performance.mark === 'function' &&
typeof performance.clearMarks === 'function' &&
typeof performance.measure === 'function' &&
@ -289,8 +287,8 @@ if (__DEV__) {
}
var markName = `${debugID}::${markType}`;
var displayName = ReactComponentTreeHook.getDisplayName(debugID) ||
'Unknown';
var displayName =
ReactComponentTreeHook.getDisplayName(debugID) || 'Unknown';
// Chrome has an issue of dropping markers recorded too fast:
// https://bugs.chromium.org/p/chromium/issues/detail?id=640652
@ -305,7 +303,9 @@ if (__DEV__) {
}
performance.clearMarks(markName);
performance.clearMeasures(measurementName);
if (measurementName) {
performance.clearMeasures(measurementName);
}
};
ReactDebugTool = {

Просмотреть файл

@ -0,0 +1,28 @@
/**
* Copyright 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactGlobalSharedState
*/
'use strict';
var ReactInternals = require('react')
.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
var ReactGlobalSharedState = {
ReactCurrentOwner: ReactInternals.ReactCurrentOwner,
};
if (__DEV__) {
Object.assign(ReactGlobalSharedState, {
ReactComponentTreeHook: ReactInternals.ReactComponentTreeHook,
ReactDebugCurrentFrame: ReactInternals.ReactDebugCurrentFrame,
});
}
module.exports = ReactGlobalSharedState;

Просмотреть файл

@ -71,13 +71,13 @@ function getExclusive(flushHistory = getLastMeasurements()) {
var stats = aggregatedStats[key];
if (!stats) {
affectedIDs[key] = {};
stats = (aggregatedStats[key] = {
stats = aggregatedStats[key] = {
key,
instanceCount: 0,
counts: {},
durations: {},
totalDuration: 0,
});
};
}
if (!stats.durations[timerType]) {
stats.durations[timerType] = 0;
@ -125,12 +125,12 @@ function getInclusive(flushHistory = getLastMeasurements()) {
var stats = aggregatedStats[key];
if (!stats) {
affectedIDs[key] = {};
stats = (aggregatedStats[key] = {
stats = aggregatedStats[key] = {
key,
instanceCount: 0,
inclusiveRenderDuration: 0,
renderCount: 0,
});
};
}
affectedIDs[key][instanceID] = true;
applyUpdate(stats);
@ -196,12 +196,12 @@ function getWasted(flushHistory = getLastMeasurements()) {
var stats = aggregatedStats[key];
if (!stats) {
affectedIDs[key] = {};
stats = (aggregatedStats[key] = {
stats = aggregatedStats[key] = {
key,
instanceCount: 0,
inclusiveRenderDuration: 0,
renderCount: 0,
});
};
}
affectedIDs[key][instanceID] = true;
applyUpdate(stats);
@ -255,7 +255,8 @@ function getWasted(flushHistory = getLastMeasurements()) {
while (nextParentID) {
// Any parents rendered during this batch are considered wasted
// unless we previously marked them as dirty.
var isWasted = renderedCompositeIDs[nextParentID] &&
var isWasted =
renderedCompositeIDs[nextParentID] &&
!isDefinitelyNotWastedByID[nextParentID];
if (isWasted) {
updateAggregatedStats(treeSnapshot, nextParentID, stats => {

Просмотреть файл

@ -0,0 +1,55 @@
/**
* Copyright 2016-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @emails react-core
*/
'use strict';
const ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
const describeFiber = ReactDOMFeatureFlags.useFiber ? describe : xdescribe;
describeFiber('ReactDOMFrameScheduling', () => {
it('throws when requestAnimationFrame is not polyfilled in the browser', () => {
const previousRAF = global.requestAnimationFrame;
try {
global.requestAnimationFrame = undefined;
jest.resetModules();
expect(() => {
require('ReactDOM');
}).toThrow(
'React depends on requestAnimationFrame. Make sure that you load a ' +
'polyfill in older browsers.',
);
} finally {
global.requestAnimationFrame = previousRAF;
}
});
// We're just testing importing, not using it.
// It is important because even isomorphic components may import it.
it('can import findDOMNode in Node environment', () => {
const previousRAF = global.requestAnimationFrame;
const previousRIC = global.requestIdleCallback;
const prevWindow = global.window;
try {
global.requestAnimationFrame = undefined;
global.requestIdleCallback = undefined;
// Simulate the Node environment:
delete global.window;
jest.resetModules();
expect(() => {
require('ReactDOM');
}).not.toThrow();
} finally {
global.requestAnimationFrame = previousRAF;
global.requestIdleCallback = previousRIC;
global.window = prevWindow;
}
});
});

Просмотреть файл

@ -20,13 +20,8 @@ import type {ReactInstance} from 'ReactInstanceType';
import type {PriorityLevel} from 'ReactPriorityLevel';
var REACT_ELEMENT_TYPE = require('ReactElementSymbol');
var {
REACT_COROUTINE_TYPE,
REACT_YIELD_TYPE,
} = require('ReactCoroutine');
var {
REACT_PORTAL_TYPE,
} = require('ReactPortal');
var {REACT_COROUTINE_TYPE, REACT_YIELD_TYPE} = require('ReactCoroutine');
var {REACT_PORTAL_TYPE} = require('ReactPortal');
var ReactFiber = require('ReactFiber');
var ReactTypeOfSideEffect = require('ReactTypeOfSideEffect');
@ -36,13 +31,49 @@ var emptyObject = require('fbjs/lib/emptyObject');
var getIteratorFn = require('getIteratorFn');
var invariant = require('fbjs/lib/invariant');
var ReactFeatureFlags = require('ReactFeatureFlags');
var ReactCurrentOwner = require('react/lib/ReactCurrentOwner');
if (__DEV__) {
var {getCurrentFiberStackAddendum} = require('ReactDebugCurrentFiber');
var getComponentName = require('getComponentName');
var warning = require('fbjs/lib/warning');
var didWarnAboutMaps = false;
/**
* Warn if there's no key explicitly set on dynamic arrays of children or
* object keys are not valid. This allows us to keep track of children between
* updates.
*/
var ownerHasKeyUseWarning = {};
var warnForMissingKey = (child: mixed) => {
if (child === null || typeof child !== 'object') {
return;
}
if (!child._store || child._store.validated || child.key != null) {
return;
}
invariant(
typeof child._store === 'object',
'React Component in warnForMissingKey should have a _store',
);
child._store.validated = true;
var currentComponentErrorInfo =
'Each child in an array or iterator should have a unique ' +
'"key" prop. See https://fb.me/react-warning-keys for ' +
'more information.' +
(getCurrentFiberStackAddendum(child) || '');
if (ownerHasKeyUseWarning[currentComponentErrorInfo]) {
return;
}
ownerHasKeyUseWarning[currentComponentErrorInfo] = true;
warning(
false,
'Each child in an array or iterator should have a unique ' +
'"key" prop. See https://fb.me/react-warning-keys for ' +
'more information.%s',
getCurrentFiberStackAddendum(child),
);
};
}
const {
@ -67,11 +98,7 @@ const {
Fragment,
} = ReactTypeOfWork;
const {
NoEffect,
Placement,
Deletion,
} = ReactTypeOfSideEffect;
const {NoEffect, Placement, Deletion} = ReactTypeOfSideEffect;
function coerceRef(current: Fiber | null, element: ReactElement) {
let mixedRef = element.ref;
@ -126,15 +153,10 @@ function throwOnInvalidObjectType(returnFiber: Fiber, newChild: Object) {
if (returnFiber.type !== 'textarea') {
let addendum = '';
if (__DEV__) {
addendum = ' If you meant to render a collection of children, use an array ' +
'instead.';
const owner = ReactCurrentOwner.owner || returnFiber._debugOwner;
if (owner && typeof owner.tag === 'number') {
const name = getComponentName((owner: any));
if (name) {
addendum += '\n\nCheck the render method of `' + name + '`.';
}
}
addendum =
' If you meant to render a collection of children, use an array ' +
'instead.' +
(getCurrentFiberStackAddendum() || '');
}
invariant(
false,
@ -172,7 +194,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
last.nextEffect = childToDelete;
returnFiber.progressedLastDeletion = childToDelete;
} else {
returnFiber.progressedFirstDeletion = (returnFiber.progressedLastDeletion = childToDelete);
returnFiber.progressedFirstDeletion = returnFiber.progressedLastDeletion = childToDelete;
}
childToDelete.nextEffect = null;
childToDelete.effectTag = Deletion;
@ -283,7 +305,11 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
) {
if (current === null || current.tag !== HostText) {
// Insert
const created = createFiberFromText(textContent, priority);
const created = createFiberFromText(
textContent,
returnFiber.internalContextTag,
priority,
);
created.return = returnFiber;
return created;
} else {
@ -303,7 +329,11 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
): Fiber {
if (current === null || current.type !== element.type) {
// Insert
const created = createFiberFromElement(element, priority);
const created = createFiberFromElement(
element,
returnFiber.internalContextTag,
priority,
);
created.ref = coerceRef(current, element);
created.return = returnFiber;
return created;
@ -330,7 +360,11 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
// TODO: Should this also compare handler to determine whether to reuse?
if (current === null || current.tag !== CoroutineComponent) {
// Insert
const created = createFiberFromCoroutine(coroutine, priority);
const created = createFiberFromCoroutine(
coroutine,
returnFiber.internalContextTag,
priority,
);
created.return = returnFiber;
return created;
} else {
@ -350,7 +384,11 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
): Fiber {
if (current === null || current.tag !== YieldComponent) {
// Insert
const created = createFiberFromYield(yieldNode, priority);
const created = createFiberFromYield(
yieldNode,
returnFiber.internalContextTag,
priority,
);
created.type = yieldNode.value;
created.return = returnFiber;
return created;
@ -376,7 +414,11 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
current.stateNode.implementation !== portal.implementation
) {
// Insert
const created = createFiberFromPortal(portal, priority);
const created = createFiberFromPortal(
portal,
returnFiber.internalContextTag,
priority,
);
created.return = returnFiber;
return created;
} else {
@ -396,7 +438,11 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
): Fiber {
if (current === null || current.tag !== Fragment) {
// Insert
const created = createFiberFromFragment(fragment, priority);
const created = createFiberFromFragment(
fragment,
returnFiber.internalContextTag,
priority,
);
created.return = returnFiber;
return created;
} else {
@ -417,7 +463,11 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
// Text nodes doesn't have keys. If the previous node is implicitly keyed
// we can continue to replace it without aborting even if it is not a text
// node.
const created = createFiberFromText('' + newChild, priority);
const created = createFiberFromText(
'' + newChild,
returnFiber.internalContextTag,
priority,
);
created.return = returnFiber;
return created;
}
@ -425,34 +475,54 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
if (typeof newChild === 'object' && newChild !== null) {
switch (newChild.$$typeof) {
case REACT_ELEMENT_TYPE: {
const created = createFiberFromElement(newChild, priority);
const created = createFiberFromElement(
newChild,
returnFiber.internalContextTag,
priority,
);
created.ref = coerceRef(null, newChild);
created.return = returnFiber;
return created;
}
case REACT_COROUTINE_TYPE: {
const created = createFiberFromCoroutine(newChild, priority);
const created = createFiberFromCoroutine(
newChild,
returnFiber.internalContextTag,
priority,
);
created.return = returnFiber;
return created;
}
case REACT_YIELD_TYPE: {
const created = createFiberFromYield(newChild, priority);
const created = createFiberFromYield(
newChild,
returnFiber.internalContextTag,
priority,
);
created.type = newChild.value;
created.return = returnFiber;
return created;
}
case REACT_PORTAL_TYPE: {
const created = createFiberFromPortal(newChild, priority);
const created = createFiberFromPortal(
newChild,
returnFiber.internalContextTag,
priority,
);
created.return = returnFiber;
return created;
}
}
if (isArray(newChild) || getIteratorFn(newChild)) {
const created = createFiberFromFragment(newChild, priority);
const created = createFiberFromFragment(
newChild,
returnFiber.internalContextTag,
priority,
);
created.return = returnFiber;
return created;
}
@ -553,16 +623,18 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
if (typeof newChild === 'object' && newChild !== null) {
switch (newChild.$$typeof) {
case REACT_ELEMENT_TYPE: {
const matchedFiber = existingChildren.get(
newChild.key === null ? newIdx : newChild.key,
) || null;
const matchedFiber =
existingChildren.get(
newChild.key === null ? newIdx : newChild.key,
) || null;
return updateElement(returnFiber, matchedFiber, newChild, priority);
}
case REACT_COROUTINE_TYPE: {
const matchedFiber = existingChildren.get(
newChild.key === null ? newIdx : newChild.key,
) || null;
const matchedFiber =
existingChildren.get(
newChild.key === null ? newIdx : newChild.key,
) || null;
return updateCoroutine(returnFiber, matchedFiber, newChild, priority);
}
@ -574,9 +646,10 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
}
case REACT_PORTAL_TYPE: {
const matchedFiber = existingChildren.get(
newChild.key === null ? newIdx : newChild.key,
) || null;
const matchedFiber =
existingChildren.get(
newChild.key === null ? newIdx : newChild.key,
) || null;
return updatePortal(returnFiber, matchedFiber, newChild, priority);
}
}
@ -592,7 +665,10 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
return null;
}
function warnOnDuplicateKey(
/**
* Warns if there is a duplicate or missing key
*/
function warnOnInvalidKey(
child: mixed,
knownKeys: Set<string> | null,
): Set<string> | null {
@ -604,6 +680,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
case REACT_ELEMENT_TYPE:
case REACT_COROUTINE_TYPE:
case REACT_PORTAL_TYPE:
warnForMissingKey(child);
const key = child.key;
if (typeof key !== 'string') {
break;
@ -663,7 +740,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
let knownKeys = null;
for (let i = 0; i < newChildren.length; i++) {
const child = newChildren[i];
knownKeys = warnOnDuplicateKey(child, knownKeys);
knownKeys = warnOnInvalidKey(child, knownKeys);
}
}
@ -813,22 +890,12 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
if (typeof newChildrenIterable.entries === 'function') {
const possibleMap = (newChildrenIterable: any);
if (possibleMap.entries === iteratorFn) {
let mapsAsChildrenAddendum = '';
const owner = ReactCurrentOwner.owner || returnFiber._debugOwner;
if (owner && typeof owner.tag === 'number') {
const mapsAsChildrenOwnerName = getComponentName((owner: any));
if (mapsAsChildrenOwnerName) {
mapsAsChildrenAddendum = '\n\nCheck the render method of `' +
mapsAsChildrenOwnerName +
'`.';
}
}
warning(
didWarnAboutMaps,
'Using Maps as children is unsupported and will likely yield ' +
'unexpected results. Convert it to a sequence/iterable of keyed ' +
'ReactElements instead.%s',
mapsAsChildrenAddendum,
getCurrentFiberStackAddendum(),
);
didWarnAboutMaps = true;
}
@ -842,7 +909,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
let step = newChildren.next();
for (; !step.done; step = newChildren.next()) {
const child = step.value;
knownKeys = warnOnDuplicateKey(child, knownKeys);
knownKeys = warnOnInvalidKey(child, knownKeys);
}
}
}
@ -992,7 +1059,11 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
// The existing first child is not a text node so we need to create one
// and delete the existing ones.
deleteRemainingChildren(returnFiber, currentFirstChild);
const created = createFiberFromText(textContent, priority);
const created = createFiberFromText(
textContent,
returnFiber.internalContextTag,
priority,
);
created.return = returnFiber;
return created;
}
@ -1030,7 +1101,11 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
child = child.sibling;
}
const created = createFiberFromElement(element, priority);
const created = createFiberFromElement(
element,
returnFiber.internalContextTag,
priority,
);
created.ref = coerceRef(currentFirstChild, element);
created.return = returnFiber;
return created;
@ -1064,7 +1139,11 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
child = child.sibling;
}
const created = createFiberFromCoroutine(coroutine, priority);
const created = createFiberFromCoroutine(
coroutine,
returnFiber.internalContextTag,
priority,
);
created.return = returnFiber;
return created;
}
@ -1089,7 +1168,11 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
}
}
const created = createFiberFromYield(yieldNode, priority);
const created = createFiberFromYield(
yieldNode,
returnFiber.internalContextTag,
priority,
);
created.type = yieldNode.value;
created.return = returnFiber;
return created;
@ -1127,7 +1210,11 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
child = child.sibling;
}
const created = createFiberFromPortal(portal, priority);
const created = createFiberFromPortal(
portal,
returnFiber.internalContextTag,
priority,
);
created.return = returnFiber;
return created;
}
@ -1228,7 +1315,8 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
if (__DEV__) {
const instance = returnFiber.stateNode;
if (
instance.render._isMockFunction && typeof newChild === 'undefined'
instance.render._isMockFunction &&
typeof newChild === 'undefined'
) {
// We allow auto-mocks to proceed as if they're
// returning null.
@ -1361,10 +1449,10 @@ exports.cloneChildFibers = function(
newChild.return = workInProgress;
while (currentChild.sibling !== null) {
currentChild = currentChild.sibling;
newChild = (newChild.sibling = cloneFiber(
newChild = newChild.sibling = cloneFiber(
currentChild,
currentChild.pendingWorkPriority,
));
);
newChild.return = workInProgress;
}
newChild.sibling = null;

Просмотреть файл

@ -41,7 +41,8 @@ if (__DEV__) {
// Longer prefixes are hard to read in DevTools.
const reactEmoji = '\u269B';
const warningEmoji = '\u26D4';
const supportsUserTiming = typeof performance !== 'undefined' &&
const supportsUserTiming =
typeof performance !== 'undefined' &&
typeof performance.mark === 'function' &&
typeof performance.clearMarks === 'function' &&
typeof performance.measure === 'function' &&

Просмотреть файл

@ -18,11 +18,11 @@ import type {ReactFragment} from 'ReactTypes';
import type {ReactCoroutine, ReactYield} from 'ReactCoroutine';
import type {ReactPortal} from 'ReactPortal';
import type {TypeOfWork} from 'ReactTypeOfWork';
import type {TypeOfInternalContext} from 'ReactTypeOfInternalContext';
import type {TypeOfSideEffect} from 'ReactTypeOfSideEffect';
import type {PriorityLevel} from 'ReactPriorityLevel';
import type {UpdateQueue} from 'ReactFiberUpdateQueue';
var ReactTypeOfWork = require('ReactTypeOfWork');
var {
IndeterminateComponent,
ClassComponent,
@ -33,24 +33,32 @@ var {
CoroutineComponent,
YieldComponent,
Fragment,
} = ReactTypeOfWork;
} = require('ReactTypeOfWork');
var {
NoWork,
} = require('ReactPriorityLevel');
var {NoWork} = require('ReactPriorityLevel');
var {
NoEffect,
} = require('ReactTypeOfSideEffect');
var {NoContext} = require('ReactTypeOfInternalContext');
var {
cloneUpdateQueue,
} = require('ReactFiberUpdateQueue');
var {NoEffect} = require('ReactTypeOfSideEffect');
var {cloneUpdateQueue} = require('ReactFiberUpdateQueue');
var invariant = require('fbjs/lib/invariant');
if (__DEV__) {
var getComponentName = require('getComponentName');
var hasBadMapPolyfill = false;
try {
const nonExtensibleObject = Object.preventExtensions({});
/* eslint-disable no-new */
new Map([[nonExtensibleObject, null]]);
new Set([nonExtensibleObject]);
/* eslint-enable no-new */
} catch (e) {
// TODO: Consider warning about bad polyfills
hasBadMapPolyfill = true;
}
}
// A Fiber is work on a Component that needs to be done or was done. There can
@ -116,6 +124,14 @@ export type Fiber = {
// The state used to create the output
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-
// 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
// before its child fibers are created.
internalContextTag: TypeOfInternalContext,
// Effect
effectTag: TypeOfSideEffect,
@ -176,7 +192,11 @@ if (__DEV__) {
// to optimize in a non-JIT environment.
// 5) It should be easy to port this to a C struct and keep a C implementation
// compatible.
var createFiber = function(tag: TypeOfWork, key: null | string): Fiber {
var createFiber = function(
tag: TypeOfWork,
key: null | string,
internalContextTag: TypeOfInternalContext,
): Fiber {
var fiber: Fiber = {
// Instance
@ -203,6 +223,8 @@ var createFiber = function(tag: TypeOfWork, key: null | string): Fiber {
updateQueue: null,
memoizedState: null,
internalContextTag,
effectTag: NoEffect,
nextEffect: null,
firstEffect: null,
@ -222,7 +244,7 @@ var createFiber = function(tag: TypeOfWork, key: null | string): Fiber {
fiber._debugSource = null;
fiber._debugOwner = null;
fiber._debugIsCurrentlyTiming = false;
if (typeof Object.preventExtensions === 'function') {
if (!hasBadMapPolyfill && typeof Object.preventExtensions === 'function') {
Object.preventExtensions(fiber);
}
}
@ -264,7 +286,7 @@ exports.cloneFiber = function(
alt.lastEffect = null;
} else {
// This should not have an alternate already
alt = createFiber(fiber.tag, fiber.key);
alt = createFiber(fiber.tag, fiber.key, fiber.internalContextTag);
alt.type = fiber.type;
alt.progressedChild = fiber.progressedChild;
@ -298,12 +320,13 @@ exports.cloneFiber = function(
};
exports.createHostRootFiber = function(): Fiber {
const fiber = createFiber(HostRoot, null);
const fiber = createFiber(HostRoot, null, NoContext);
return fiber;
};
exports.createFiberFromElement = function(
element: ReactElement,
internalContextTag: TypeOfInternalContext,
priorityLevel: PriorityLevel,
): Fiber {
let owner = null;
@ -311,7 +334,12 @@ exports.createFiberFromElement = function(
owner = element._owner;
}
const fiber = createFiberFromElementType(element.type, element.key, owner);
const fiber = createFiberFromElementType(
element.type,
element.key,
internalContextTag,
owner,
);
fiber.pendingProps = element.props;
fiber.pendingWorkPriority = priorityLevel;
@ -325,11 +353,12 @@ exports.createFiberFromElement = function(
exports.createFiberFromFragment = function(
elements: ReactFragment,
internalContextTag: TypeOfInternalContext,
priorityLevel: PriorityLevel,
): Fiber {
// TODO: Consider supporting keyed fragments. Technically, we accidentally
// support that in the existing React.
const fiber = createFiber(Fragment, null);
const fiber = createFiber(Fragment, null, internalContextTag);
fiber.pendingProps = elements;
fiber.pendingWorkPriority = priorityLevel;
return fiber;
@ -337,9 +366,10 @@ exports.createFiberFromFragment = function(
exports.createFiberFromText = function(
content: string,
internalContextTag: TypeOfInternalContext,
priorityLevel: PriorityLevel,
): Fiber {
const fiber = createFiber(HostText, null);
const fiber = createFiber(HostText, null, internalContextTag);
fiber.pendingProps = content;
fiber.pendingWorkPriority = priorityLevel;
return fiber;
@ -348,19 +378,22 @@ exports.createFiberFromText = function(
function createFiberFromElementType(
type: mixed,
key: null | string,
internalContextTag: TypeOfInternalContext,
debugOwner: null | Fiber | ReactInstance,
): Fiber {
let fiber;
if (typeof type === 'function') {
fiber = shouldConstruct(type)
? createFiber(ClassComponent, key)
: createFiber(IndeterminateComponent, key);
? createFiber(ClassComponent, key, internalContextTag)
: createFiber(IndeterminateComponent, key, internalContextTag);
fiber.type = type;
} else if (typeof type === 'string') {
fiber = createFiber(HostComponent, key);
fiber = createFiber(HostComponent, key, internalContextTag);
fiber.type = type;
} else if (
typeof type === 'object' && type !== null && typeof type.tag === 'number'
typeof type === 'object' &&
type !== null &&
typeof type.tag === 'number'
) {
// Currently assumed to be a continuation and therefore is a fiber already.
// TODO: The yield system is currently broken for updates in some cases.
@ -378,7 +411,8 @@ function createFiberFromElementType(
type !== null &&
Object.keys(type).length === 0)
) {
info += ' You likely forgot to export your component from the file ' +
info +=
' You likely forgot to export your component from the file ' +
"it's defined in.";
}
const ownerName = debugOwner ? getComponentName(debugOwner) : null;
@ -401,9 +435,14 @@ exports.createFiberFromElementType = createFiberFromElementType;
exports.createFiberFromCoroutine = function(
coroutine: ReactCoroutine,
internalContextTag: TypeOfInternalContext,
priorityLevel: PriorityLevel,
): Fiber {
const fiber = createFiber(CoroutineComponent, coroutine.key);
const fiber = createFiber(
CoroutineComponent,
coroutine.key,
internalContextTag,
);
fiber.type = coroutine.handler;
fiber.pendingProps = coroutine;
fiber.pendingWorkPriority = priorityLevel;
@ -412,17 +451,19 @@ exports.createFiberFromCoroutine = function(
exports.createFiberFromYield = function(
yieldNode: ReactYield,
internalContextTag: TypeOfInternalContext,
priorityLevel: PriorityLevel,
): Fiber {
const fiber = createFiber(YieldComponent, null);
const fiber = createFiber(YieldComponent, null, internalContextTag);
return fiber;
};
exports.createFiberFromPortal = function(
portal: ReactPortal,
internalContextTag: TypeOfInternalContext,
priorityLevel: PriorityLevel,
): Fiber {
const fiber = createFiber(HostPortal, portal.key);
const fiber = createFiber(HostPortal, portal.key, internalContextTag);
fiber.pendingProps = portal.children || [];
fiber.pendingWorkPriority = priorityLevel;
fiber.stateNode = {

Просмотреть файл

@ -25,9 +25,7 @@ var {
reconcileChildFibersInPlace,
cloneChildFibers,
} = require('ReactChildFiber');
var {
beginUpdateQueue,
} = require('ReactFiberUpdateQueue');
var {beginUpdateQueue} = require('ReactFiberUpdateQueue');
var ReactTypeOfWork = require('ReactTypeOfWork');
var {
getMaskedContext,
@ -50,18 +48,10 @@ var {
YieldComponent,
Fragment,
} = ReactTypeOfWork;
var {
NoWork,
OffscreenPriority,
} = require('ReactPriorityLevel');
var {
Placement,
ContentReset,
Err,
Ref,
} = require('ReactTypeOfSideEffect');
var ReactCurrentOwner = require('react/lib/ReactCurrentOwner');
var {NoWork, OffscreenPriority} = require('ReactPriorityLevel');
var {Placement, ContentReset, Err, Ref} = require('ReactTypeOfSideEffect');
var ReactFiberClassComponent = require('ReactFiberClassComponent');
var {ReactCurrentOwner} = require('ReactGlobalSharedState');
var invariant = require('fbjs/lib/invariant');
if (__DEV__) {
@ -76,7 +66,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
config: HostConfig<T, P, I, TI, PI, C, CX, PL>,
hostContext: HostContext<C, CX>,
scheduleUpdate: (fiber: Fiber, priorityLevel: PriorityLevel) => void,
getPriorityContext: () => PriorityLevel,
getPriorityContext: (fiber: Fiber, forceAsync: boolean) => PriorityLevel,
) {
const {
shouldSetTextContent,
@ -84,10 +74,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
shouldDeprioritizeSubtree,
} = config;
const {
pushHostContext,
pushHostContainer,
} = hostContext;
const {pushHostContext, pushHostContainer} = hostContext;
const {
adoptClassInstance,
@ -115,7 +102,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
}
function clearDeletions(workInProgress) {
workInProgress.progressedFirstDeletion = (workInProgress.progressedLastDeletion = null);
workInProgress.progressedFirstDeletion = workInProgress.progressedLastDeletion = null;
}
function transferDeletions(workInProgress) {
@ -196,7 +183,8 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
nextChildren = workInProgress.memoizedProps;
}
} else if (
nextChildren === null || workInProgress.memoizedProps === nextChildren
nextChildren === null ||
workInProgress.memoizedProps === nextChildren
) {
return bailoutOnAlreadyFinishedWork(current, workInProgress);
}
@ -272,7 +260,7 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
if (current === null) {
if (!workInProgress.stateNode) {
// In the initial pass we might need to construct the instance.
constructClassInstance(workInProgress);
constructClassInstance(workInProgress, workInProgress.pendingProps);
mountClassInstance(workInProgress, priorityLevel);
shouldUpdate = true;
} else {
@ -585,7 +573,8 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
);
}
} else if (
nextCoroutine === null || workInProgress.memoizedProps === nextCoroutine
nextCoroutine === null ||
workInProgress.memoizedProps === nextCoroutine
) {
nextCoroutine = workInProgress.memoizedProps;
// TODO: When bailing out, we might need to return the stateNode instead
@ -653,7 +642,8 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
);
}
} else if (
nextChildren === null || workInProgress.memoizedProps === nextChildren
nextChildren === null ||
workInProgress.memoizedProps === nextChildren
) {
return bailoutOnAlreadyFinishedWork(current, workInProgress);
}

Просмотреть файл

@ -15,9 +15,11 @@
import type {Fiber} from 'ReactFiber';
import type {PriorityLevel} from 'ReactPriorityLevel';
var {
Update,
} = require('ReactTypeOfSideEffect');
var {Update} = require('ReactTypeOfSideEffect');
var ReactFeatureFlags = require('ReactFeatureFlags');
var {AsyncUpdates} = require('ReactTypeOfInternalContext');
var {
cacheContext,
getMaskedContext,
@ -41,10 +43,7 @@ var invariant = require('fbjs/lib/invariant');
const isArray = Array.isArray;
if (__DEV__) {
var {
startPhaseTimer,
stopPhaseTimer,
} = require('ReactDebugFiberPerf');
var {startPhaseTimer, stopPhaseTimer} = require('ReactDebugFiberPerf');
var warning = require('fbjs/lib/warning');
var warnOnInvalidCallback = function(callback: mixed, callerName: string) {
warning(
@ -59,7 +58,7 @@ if (__DEV__) {
module.exports = function(
scheduleUpdate: (fiber: Fiber, priorityLevel: PriorityLevel) => void,
getPriorityContext: () => PriorityLevel,
getPriorityContext: (fiber: Fiber, forceAsync: boolean) => PriorityLevel,
memoizeProps: (workInProgress: Fiber, props: any) => void,
memoizeState: (workInProgress: Fiber, state: any) => void,
) {
@ -68,7 +67,7 @@ module.exports = function(
isMounted,
enqueueSetState(instance, partialState, callback) {
const fiber = ReactInstanceMap.get(instance);
const priorityLevel = getPriorityContext();
const priorityLevel = getPriorityContext(fiber, false);
callback = callback === undefined ? null : callback;
if (__DEV__) {
warnOnInvalidCallback(callback, 'setState');
@ -78,7 +77,7 @@ module.exports = function(
},
enqueueReplaceState(instance, state, callback) {
const fiber = ReactInstanceMap.get(instance);
const priorityLevel = getPriorityContext();
const priorityLevel = getPriorityContext(fiber, false);
callback = callback === undefined ? null : callback;
if (__DEV__) {
warnOnInvalidCallback(callback, 'replaceState');
@ -88,7 +87,7 @@ module.exports = function(
},
enqueueForceUpdate(instance, callback) {
const fiber = ReactInstanceMap.get(instance);
const priorityLevel = getPriorityContext();
const priorityLevel = getPriorityContext(fiber, false);
callback = callback === undefined ? null : callback;
if (__DEV__) {
warnOnInvalidCallback(callback, 'forceUpdate');
@ -116,6 +115,7 @@ module.exports = function(
}
const instance = workInProgress.stateNode;
const type = workInProgress.type;
if (typeof instance.shouldComponentUpdate === 'function') {
if (__DEV__) {
startPhaseTimer(workInProgress, 'shouldComponentUpdate');
@ -141,10 +141,10 @@ module.exports = function(
return shouldUpdate;
}
const type = workInProgress.type;
if (type.prototype && type.prototype.isPureReactComponent) {
return !shallowEqual(oldProps, newProps) ||
!shallowEqual(oldState, newState);
return (
!shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState)
);
}
return true;
@ -152,6 +152,7 @@ module.exports = function(
function checkClassInstance(workInProgress: Fiber) {
const instance = workInProgress.stateNode;
const type = workInProgress.type;
if (__DEV__) {
const name = getComponentName(workInProgress);
const renderPresent = instance.render;
@ -161,7 +162,8 @@ module.exports = function(
'instance: you may have forgotten to define `render`.',
name,
);
const noGetInitialStateOnES6 = !instance.getInitialState ||
const noGetInitialStateOnES6 =
!instance.getInitialState ||
instance.getInitialState.isReactClassApproved ||
instance.state;
warning(
@ -171,7 +173,8 @@ module.exports = function(
'Did you mean to define a state property instead?',
name,
);
const noGetDefaultPropsOnES6 = !instance.getDefaultProps ||
const noGetDefaultPropsOnES6 =
!instance.getDefaultProps ||
instance.getDefaultProps.isReactClassApproved;
warning(
noGetDefaultPropsOnES6,
@ -194,8 +197,8 @@ module.exports = function(
'property to define contextTypes instead.',
name,
);
const noComponentShouldUpdate = typeof instance.componentShouldUpdate !==
'function';
const noComponentShouldUpdate =
typeof instance.componentShouldUpdate !== 'function';
warning(
noComponentShouldUpdate,
'%s has a method called ' +
@ -204,8 +207,21 @@ module.exports = function(
'expected to return a value.',
name,
);
const noComponentDidUnmount = typeof instance.componentDidUnmount !==
'function';
if (
type.prototype &&
type.prototype.isPureReactComponent &&
typeof instance.shouldComponentUpdate !== 'undefined'
) {
warning(
false,
'%s has a method called shouldComponentUpdate(). ' +
'shouldComponentUpdate should not be used when extending React.PureComponent. ' +
'Please extend React.Component if shouldComponentUpdate is used.',
getComponentName(workInProgress) || 'A pure component',
);
}
const noComponentDidUnmount =
typeof instance.componentDidUnmount !== 'function';
warning(
noComponentDidUnmount,
'%s has a method called ' +
@ -213,8 +229,8 @@ module.exports = function(
'Did you mean componentWillUnmount()?',
name,
);
const noComponentWillRecieveProps = typeof instance.componentWillRecieveProps !==
'function';
const noComponentWillRecieveProps =
typeof instance.componentWillRecieveProps !== 'function';
warning(
noComponentWillRecieveProps,
'%s has a method called ' +
@ -229,6 +245,14 @@ module.exports = function(
name,
name,
);
const noInstanceDefaultProps = !instance.defaultProps;
warning(
noInstanceDefaultProps,
'Setting defaultProps as an instance property on %s is not supported and will be ignored.' +
' Instead, define defaultProps as a static property on %s.',
name,
name,
);
}
const state = instance.state;
@ -261,9 +285,8 @@ module.exports = function(
ReactInstanceMap.set(instance, workInProgress);
}
function constructClassInstance(workInProgress: Fiber): any {
function constructClassInstance(workInProgress: Fiber, props: any): any {
const ctor = workInProgress.type;
const props = workInProgress.pendingProps;
const unmaskedContext = getUnmaskedContext(workInProgress);
const needsContext = isContextConsumer(workInProgress);
const context = needsContext
@ -271,7 +294,6 @@ module.exports = function(
: emptyObject;
const instance = new ctor(props, context);
adoptClassInstance(workInProgress, instance);
checkClassInstance(workInProgress);
// Cache unmasked context so we can avoid recreating masked context unless necessary.
// ReactFiberContext usually updates this cache but can't for newly-created instances.
@ -287,6 +309,10 @@ module.exports = function(
workInProgress: Fiber,
priorityLevel: PriorityLevel,
): void {
if (__DEV__) {
checkClassInstance(workInProgress);
}
const instance = workInProgress.stateNode;
const state = instance.state || null;
@ -304,6 +330,14 @@ module.exports = function(
instance.refs = emptyObject;
instance.context = getMaskedContext(workInProgress, unmaskedContext);
if (
ReactFeatureFlags.enableAsyncSubtreeAPI &&
workInProgress.type != null &&
workInProgress.type.unstable_asyncUpdates === true
) {
workInProgress.internalContextTag |= AsyncUpdates;
}
if (typeof instance.componentWillMount === 'function') {
if (__DEV__) {
startPhaseTimer(workInProgress, 'componentWillMount');
@ -379,9 +413,9 @@ module.exports = function(
// If we didn't bail out we need to construct a new instance. We don't
// want to reuse one that failed to fully mount.
const newInstance = constructClassInstance(workInProgress);
const newInstance = constructClassInstance(workInProgress, newProps);
newInstance.props = newProps;
newInstance.state = (newState = newInstance.state || null);
newInstance.state = newState = newInstance.state || null;
newInstance.context = newContext;
if (typeof newInstance.componentWillMount === 'function') {

Просмотреть файл

@ -38,10 +38,7 @@ var {
var invariant = require('fbjs/lib/invariant');
if (__DEV__) {
var {
startPhaseTimer,
stopPhaseTimer,
} = require('ReactDebugFiberPerf');
var {startPhaseTimer, stopPhaseTimer} = require('ReactDebugFiberPerf');
}
module.exports = function<T, P, I, TI, PI, C, CX, PL>(
@ -143,9 +140,11 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
}
function isHostParent(fiber: Fiber): boolean {
return fiber.tag === HostComponent ||
return (
fiber.tag === HostComponent ||
fiber.tag === HostRoot ||
fiber.tag === HostPortal;
fiber.tag === HostPortal
);
}
function getHostSibling(fiber: Fiber): ?I {
@ -468,7 +467,8 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
}
}
if (
finishedWork.effectTag & Callback && finishedWork.updateQueue !== null
finishedWork.effectTag & Callback &&
finishedWork.updateQueue !== null
) {
commitCallbacks(finishedWork, finishedWork.updateQueue, instance);
}

Просмотреть файл

@ -19,9 +19,7 @@ import type {FiberRoot} from 'ReactFiberRoot';
import type {HostConfig} from 'ReactFiberReconciler';
var {reconcileChildFibers} = require('ReactChildFiber');
var {
popContextProvider,
} = require('ReactFiberContext');
var {popContextProvider} = require('ReactFiberContext');
var ReactTypeOfWork = require('ReactTypeOfWork');
var ReactTypeOfSideEffect = require('ReactTypeOfSideEffect');
var {
@ -37,10 +35,7 @@ var {
YieldComponent,
Fragment,
} = ReactTypeOfWork;
var {
Ref,
Update,
} = ReactTypeOfSideEffect;
var {Ref, Update} = ReactTypeOfSideEffect;
if (__DEV__) {
var ReactDebugCurrentFiber = require('ReactDebugCurrentFiber');
@ -342,7 +337,6 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
markUpdate(workInProgress);
popHostContainer(workInProgress);
return null;
// Error cases
case IndeterminateComponent:
invariant(

Просмотреть файл

@ -15,31 +15,19 @@
import type {Fiber} from 'ReactFiber';
import type {StackCursor} from 'ReactFiberStack';
var checkPropTypes = require('prop-types/checkPropTypes');
var emptyObject = require('fbjs/lib/emptyObject');
var getComponentName = require('getComponentName');
var invariant = require('fbjs/lib/invariant');
var warning = require('fbjs/lib/warning');
var {
isFiberMounted,
} = require('ReactFiberTreeReflection');
var {
ClassComponent,
HostRoot,
} = require('ReactTypeOfWork');
const {
createCursor,
pop,
push,
} = require('ReactFiberStack');
var {isFiberMounted} = require('ReactFiberTreeReflection');
var {ClassComponent, HostRoot} = require('ReactTypeOfWork');
const {createCursor, pop, push} = require('ReactFiberStack');
if (__DEV__) {
var checkReactTypeSpec = require('checkReactTypeSpec');
var ReactDebugCurrentFrame = require('react/lib/ReactDebugCurrentFrame');
var ReactDebugCurrentFiber = require('ReactDebugCurrentFiber');
var {
startPhaseTimer,
stopPhaseTimer,
} = require('ReactDebugFiberPerf');
var {ReactDebugCurrentFrame} = require('ReactGlobalSharedState');
var {startPhaseTimer, stopPhaseTimer} = require('ReactDebugFiberPerf');
var warnedAboutMissingGetChildContext = {};
}
@ -105,7 +93,13 @@ exports.getMaskedContext = function(
if (__DEV__) {
const name = getComponentName(workInProgress) || 'Unknown';
ReactDebugCurrentFrame.current = workInProgress;
checkReactTypeSpec(contextTypes, context, 'context', name);
checkPropTypes(
contextTypes,
context,
'context',
name,
ReactDebugCurrentFrame.getStackAddendum,
);
ReactDebugCurrentFrame.current = null;
}
@ -212,7 +206,13 @@ function processChildContext(
// TODO: remove this hack when we delete unstable_renderSubtree in Fiber.
const workInProgress = isReconciling ? fiber : null;
ReactDebugCurrentFrame.current = workInProgress;
checkReactTypeSpec(childContextTypes, childContext, 'child context', name);
checkPropTypes(
childContextTypes,
childContext,
'child context',
name,
ReactDebugCurrentFrame.getStackAddendum,
);
ReactDebugCurrentFrame.current = null;
}
@ -229,8 +229,8 @@ exports.pushContextProvider = function(workInProgress: Fiber): boolean {
// We push the context as early as possible to ensure stack integrity.
// If the instance does not exist yet, we will push null at first,
// and replace it on the stack later when invalidating the context.
const memoizedMergedChildContext = (instance &&
instance.__reactInternalMemoizedMergedChildContext) ||
const memoizedMergedChildContext =
(instance && instance.__reactInternalMemoizedMergedChildContext) ||
emptyObject;
// Remember the parent context so we can merge with it later.

Просмотреть файл

@ -39,11 +39,7 @@ function logCapturedError(capturedError: CapturedError): void {
willRetry,
} = capturedError;
const {
message,
name,
stack,
} = error;
const {message, name, stack} = error;
const errorSummary = message ? `${name}: ${message}` : name;
@ -69,15 +65,18 @@ function logCapturedError(capturedError: CapturedError): void {
// errorBoundaryFound check is sufficient; errorBoundaryName check is to satisfy Flow.
if (errorBoundaryFound && errorBoundaryName) {
if (willRetry) {
errorBoundaryMessage = `React will try to recreate this component tree from scratch ` +
errorBoundaryMessage =
`React will try to recreate this component tree from scratch ` +
`using the error boundary you provided, ${errorBoundaryName}.`;
} else {
errorBoundaryMessage = `This error was initially handled by the error boundary ${errorBoundaryName}. ` +
errorBoundaryMessage =
`This error was initially handled by the error boundary ${errorBoundaryName}. ` +
`Recreating the tree from scratch failed so React will unmount the tree.`;
}
} else {
// TODO Link to unstable_handleError() documentation once it exists.
errorBoundaryMessage = 'Consider adding an error boundary to your tree to customize error handling behavior.';
errorBoundaryMessage =
'Consider adding an error boundary to your tree to customize error handling behavior.';
}
console.error(
@ -98,7 +97,7 @@ function logCapturedError(capturedError: CapturedError): void {
exports.injection = {
/**
* Display custom dialog for lifecycle errors.
* Display custom dialog for lifecycle errors.
* Return false to prevent default behavior of logging to console.error.
*/
injectDialog(fn: (e: CapturedError) => boolean) {

Просмотреть файл

@ -16,16 +16,13 @@ import type {Fiber} from 'ReactFiber';
import type {HostConfig} from 'ReactFiberReconciler';
import type {StackCursor} from 'ReactFiberStack';
const emptyObject = require('fbjs/lib/emptyObject');
const {
createCursor,
pop,
push,
} = require('ReactFiberStack');
const {createCursor, pop, push} = require('ReactFiberStack');
const invariant = require('fbjs/lib/invariant');
declare class NoContextT {}
const NO_CONTEXT: NoContextT = ({}: any);
export type HostContext<C, CX> = {
getHostContext(): CX,
getRootHostContainer(): C,
@ -39,24 +36,29 @@ export type HostContext<C, CX> = {
module.exports = function<T, P, I, TI, PI, C, CX, PL>(
config: HostConfig<T, P, I, TI, PI, C, CX, PL>,
): HostContext<C, CX> {
const {
getChildHostContext,
getRootHostContext,
} = config;
const {getChildHostContext, getRootHostContext} = config;
let contextStackCursor: StackCursor<CX | null> = createCursor((null: ?CX));
let contextFiberStackCursor: StackCursor<Fiber | null> = createCursor(
(null: Fiber | null),
let contextStackCursor: StackCursor<CX | NoContextT> = createCursor(
NO_CONTEXT,
);
let rootInstanceStackCursor: StackCursor<C | null> = createCursor((null: ?C));
let contextFiberStackCursor: StackCursor<Fiber | NoContextT> = createCursor(
NO_CONTEXT,
);
let rootInstanceStackCursor: StackCursor<C | NoContextT> = createCursor(
NO_CONTEXT,
);
function requiredContext<Value>(c: Value | NoContextT): Value {
invariant(
c !== NO_CONTEXT,
'Expected host context to exist. This error is likely caused by a bug ' +
'in React. Please file an issue.',
);
return (c: any);
}
function getRootHostContainer(): C {
const rootInstance = rootInstanceStackCursor.current;
invariant(
rootInstance !== null,
'Expected root container to exist. This error is likely caused by a ' +
'bug in React. Please file an issue.',
);
const rootInstance = requiredContext(rootInstanceStackCursor.current);
return rootInstance;
}
@ -80,26 +82,13 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
}
function getHostContext(): CX {
const context = contextStackCursor.current;
invariant(
context != null,
'Expected host context to exist. This error is likely caused by a bug ' +
'in React. Please file an issue.',
);
const context = requiredContext(contextStackCursor.current);
return context;
}
function pushHostContext(fiber: Fiber): void {
const rootInstance = rootInstanceStackCursor.current;
invariant(
rootInstance != null,
'Expected root host context to exist. This error is likely caused by ' +
'a bug in React. Please file an issue.',
);
const context = contextStackCursor.current !== null
? contextStackCursor.current
: emptyObject;
const rootInstance = requiredContext(rootInstanceStackCursor.current);
const context = requiredContext(contextStackCursor.current);
const nextContext = getChildHostContext(context, fiber.type, rootInstance);
// Don't push this Fiber's context unless it's unique.
@ -125,8 +114,8 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
}
function resetHostContainer() {
contextStackCursor.current = null;
rootInstanceStackCursor.current = null;
contextStackCursor.current = NO_CONTEXT;
rootInstanceStackCursor.current = NO_CONTEXT;
}
return {

Просмотреть файл

@ -17,9 +17,9 @@ import type {FiberRoot} from 'ReactFiberRoot';
import type {PriorityLevel} from 'ReactPriorityLevel';
import type {ReactNodeList} from 'ReactTypes';
var {
addTopLevelUpdate,
} = require('ReactFiberUpdateQueue');
var ReactFeatureFlags = require('ReactFeatureFlags');
var {addTopLevelUpdate} = require('ReactFiberUpdateQueue');
var {
findCurrentUnmaskedContext,
@ -107,9 +107,9 @@ export type HostConfig<T, P, I, TI, PI, C, CX, PL> = {
removeChild(parentInstance: I | C, child: I | TI): void,
scheduleAnimationCallback(callback: () => void): number | void,
scheduleDeferredCallback(callback: (deadline: Deadline) => void):
| number
| void,
scheduleDeferredCallback(
callback: (deadline: Deadline) => void,
): number | void,
prepareForCommit(): void,
resetAfterCommit(): void,
@ -123,6 +123,7 @@ export type Reconciler<C, I, TI> = {
element: ReactNodeList,
container: OpaqueRoot,
parentComponent: ?ReactComponent<any, any, any>,
callback: ?Function,
): void,
performWithPriority(priorityLevel: PriorityLevel, fn: Function): void,
batchedUpdates<A>(fn: () => A): A,
@ -131,11 +132,9 @@ export type Reconciler<C, I, TI> = {
deferredUpdates<A>(fn: () => A): A,
// Used to extract the return value from the initial render. Legacy API.
getPublicRootInstance(container: OpaqueRoot):
| ReactComponent<any, any, any>
| TI
| I
| null,
getPublicRootInstance(
container: OpaqueRoot,
): ReactComponent<any, any, any> | TI | I | null,
// Use for findDOMNode/findHostNode. Legacy API.
findHostInstance(component: Fiber): I | TI | null,
@ -182,7 +181,15 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
}
}
const priorityLevel = getPriorityContext();
// 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 =
(ReactFeatureFlags : any).enableAsyncSubtreeAPI &&
element != null &&
element.type != null &&
(element.type: any).unstable_asyncUpdates === true;
const priorityLevel = getPriorityContext(current, forceAsync);
const nextState = {element};
callback = callback === undefined ? null : callback;
if (__DEV__) {

Просмотреть файл

@ -31,9 +31,7 @@ export type HandleErrorInfo = {
componentStack: string,
};
var {
popContextProvider,
} = require('ReactFiberContext');
var {popContextProvider} = require('ReactFiberContext');
const {reset} = require('ReactFiberStack');
var {
getStackAddendumByWorkInProgressFiber,
@ -45,8 +43,8 @@ var ReactFiberBeginWork = require('ReactFiberBeginWork');
var ReactFiberCompleteWork = require('ReactFiberCompleteWork');
var ReactFiberCommitWork = require('ReactFiberCommitWork');
var ReactFiberHostContext = require('ReactFiberHostContext');
var ReactCurrentOwner = require('react/lib/ReactCurrentOwner');
var ReactFeatureFlags = require('ReactFeatureFlags');
var {ReactCurrentOwner} = require('ReactGlobalSharedState');
var getComponentName = require('getComponentName');
var {cloneFiber} = require('ReactFiber');
@ -62,6 +60,8 @@ var {
OffscreenPriority,
} = require('ReactPriorityLevel');
var {AsyncUpdates} = require('ReactTypeOfInternalContext');
var {
NoEffect,
Placement,
@ -81,13 +81,9 @@ var {
ClassComponent,
} = require('ReactTypeOfWork');
var {
getPendingPriority,
} = require('ReactFiberUpdateQueue');
var {getPendingPriority} = require('ReactFiberUpdateQueue');
var {
resetContext,
} = require('ReactFiberContext');
var {resetContext} = require('ReactFiberContext');
var invariant = require('fbjs/lib/invariant');
@ -173,11 +169,11 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
resetAfterCommit,
} = config;
// The priority level to use when scheduling an update.
// TODO: Should we change this to an array? Might be less confusing.
let priorityContext: PriorityLevel = useSyncScheduling
? SynchronousPriority
: LowPriority;
// The priority level to use when scheduling an update. We use NoWork to
// represent the default priority.
// TODO: Should we change this to an array instead of using the call stack?
// Might be less confusing.
let priorityContext: PriorityLevel = NoWork;
// Keep track of this so we can reset the priority context if an error
// is thrown during reconciliation.
@ -686,6 +682,8 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
}
// Without this explicit null return Flow complains of invalid return type
// TODO Remove the above while(true) loop
// eslint-disable-next-line no-unreachable
return null;
}
@ -1146,17 +1144,21 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
function hasCapturedError(fiber: Fiber): boolean {
// TODO: capturedErrors should store the boundary instance, to avoid needing
// to check the alternate.
return capturedErrors !== null &&
return (
capturedErrors !== null &&
(capturedErrors.has(fiber) ||
(fiber.alternate !== null && capturedErrors.has(fiber.alternate)));
(fiber.alternate !== null && capturedErrors.has(fiber.alternate)))
);
}
function isFailedBoundary(fiber: Fiber): boolean {
// TODO: failedBoundaries should store the boundary instance, to avoid
// needing to check the alternate.
return failedBoundaries !== null &&
return (
failedBoundaries !== null &&
(failedBoundaries.has(fiber) ||
(fiber.alternate !== null && failedBoundaries.has(fiber.alternate)));
(fiber.alternate !== null && failedBoundaries.has(fiber.alternate)))
);
}
function commitErrorHandling(effectfulFiber: Fiber) {
@ -1340,16 +1342,32 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
}
}
function getPriorityContext(): PriorityLevel {
function getPriorityContext(
fiber: Fiber,
forceAsync: boolean,
): PriorityLevel {
let priorityLevel = priorityContext;
if (priorityLevel === NoWork) {
if (
!useSyncScheduling ||
fiber.internalContextTag & AsyncUpdates ||
forceAsync
) {
priorityLevel = LowPriority;
} else {
priorityLevel = SynchronousPriority;
}
}
// If we're in a batch, or if we're already performing work, downgrade sync
// priority to task priority
if (
priorityContext === SynchronousPriority &&
priorityLevel === SynchronousPriority &&
(isPerformingWork || isBatchingUpdates)
) {
return TaskPriority;
}
return priorityContext;
return priorityLevel;
}
function scheduleErrorRecovery(fiber: Fiber) {

Просмотреть файл

@ -15,7 +15,7 @@
import type {Fiber} from 'ReactFiber';
var ReactInstanceMap = require('ReactInstanceMap');
var ReactCurrentOwner = require('react/lib/ReactCurrentOwner');
var {ReactCurrentOwner} = require('ReactGlobalSharedState');
var getComponentName = require('getComponentName');
var invariant = require('fbjs/lib/invariant');
@ -31,10 +31,7 @@ var {
ClassComponent,
} = require('ReactTypeOfWork');
var {
NoEffect,
Placement,
} = require('ReactTypeOfSideEffect');
var {NoEffect, Placement} = require('ReactTypeOfSideEffect');
var MOUNTING = 1;
var MOUNTED = 2;

Просмотреть файл

@ -15,9 +15,7 @@
import type {Fiber} from 'ReactFiber';
import type {PriorityLevel} from 'ReactPriorityLevel';
const {
Callback: CallbackEffect,
} = require('ReactTypeOfSideEffect');
const {Callback: CallbackEffect} = require('ReactTypeOfSideEffect');
const {
NoWork,
@ -431,7 +429,8 @@ function beginUpdateQueue(
let callbackList = null;
let update = queue.first;
while (
update !== null && comparePriority(update.priorityLevel, priorityLevel) <= 0
update !== null &&
comparePriority(update.priorityLevel, priorityLevel) <= 0
) {
// Remove each update from the queue right before it is processed. That way
// if setState is called from inside an updater function, the new update

Просмотреть файл

@ -0,0 +1,20 @@
/**
* Copyright 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactTypeOfInternalContext
* @flow
*/
'use strict';
export type TypeOfInternalContext = number;
module.exports = {
NoContext: 0,
AsyncUpdates: 1,
};

Просмотреть файл

@ -12,16 +12,16 @@
'use strict';
export type TypeOfSideEffect = 0 | 1 | 2 | 3 | 4 | 8 | 16 | 32 | 64;
export type TypeOfSideEffect = number;
module.exports = {
NoEffect: 0, // 0b0000000
Placement: 1, // 0b0000001
Update: 2, // 0b0000010
NoEffect: 0, // 0b0000000
Placement: 1, // 0b0000001
Update: 2, // 0b0000010
PlacementAndUpdate: 3, // 0b0000011
Deletion: 4, // 0b0000100
ContentReset: 8, // 0b0001000
Callback: 16, // 0b0010000
Err: 32, // 0b0100000
Ref: 64, // 0b1000000
Deletion: 4, // 0b0000100
ContentReset: 8, // 0b0001000
Callback: 16, // 0b0010000
Err: 32, // 0b0100000
Ref: 64, // 0b1000000
};

Просмотреть файл

@ -27,7 +27,7 @@ describe('ReactCoroutine', () => {
});
function div(...children) {
children = children.map(c => typeof c === 'string' ? {text: c} : c);
children = children.map(c => (typeof c === 'string' ? {text: c} : c));
return {type: 'div', children, prop: undefined};
}
@ -57,13 +57,13 @@ describe('ReactCoroutine', () => {
function Indirection() {
ops.push('Indirection');
return [<Child bar={true} />, <Child bar={false} />];
return [<Child key="a" bar={true} />, <Child key="b" bar={false} />];
}
function HandleYields(props, yields) {
ops.push('HandleYields');
return yields.map(y => (
<y.continuation isSame={props.foo === y.props.bar} />
return yields.map((y, i) => (
<y.continuation key={i} isSame={props.foo === y.props.bar} />
));
}
@ -117,12 +117,12 @@ describe('ReactCoroutine', () => {
}
function Indirection() {
return [<Child bar={true} />, <Child bar={false} />];
return [<Child key="a" bar={true} />, <Child key="b" bar={false} />];
}
function HandleYields(props, yields) {
return yields.map(y => (
<y.continuation isSame={props.foo === y.props.bar} />
return yields.map((y, i) => (
<y.continuation key={i} isSame={props.foo === y.props.bar} />
));
}
@ -176,7 +176,9 @@ describe('ReactCoroutine', () => {
function HandleYields(props, yields) {
ops.push('HandleYields');
return yields.map(ContinuationComponent => <ContinuationComponent />);
return yields.map((ContinuationComponent, i) => (
<ContinuationComponent key={i} />
));
}
class Parent extends React.Component {
@ -223,8 +225,12 @@ describe('ReactCoroutine', () => {
function App(props) {
return ReactCoroutine.createCoroutine(
[<Counter id="a" />, <Counter id="b" />, <Counter id="c" />],
(p, yields) => yields.map(y => <span prop={y * 100} />),
[
<Counter key="a" id="a" />,
<Counter key="b" id="b" />,
<Counter key="c" id="c" />,
],
(p, yields) => yields.map((y, i) => <span key={i} prop={y * 100} />),
{},
);
}

Просмотреть файл

@ -0,0 +1,62 @@
/**
* Copyright 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @emails react-core
*/
'use strict';
var React;
var ReactFiberReconciler;
describe('ReactFiberHostContext', () => {
beforeEach(() => {
jest.resetModules();
React = require('React');
ReactFiberReconciler = require('ReactFiberReconciler');
});
it('works with null host context', () => {
var creates = 0;
var Renderer = ReactFiberReconciler({
prepareForCommit: function() {},
resetAfterCommit: function() {},
getRootHostContext: function() {
return null;
},
getChildHostContext: function() {
return null;
},
shouldSetTextContent: function() {
return false;
},
createInstance: function() {
creates++;
},
finalizeInitialChildren: function() {
return null;
},
appendInitialChild: function() {
return null;
},
appendChild: function() {
return null;
},
useSyncScheduling: true,
});
const container = Renderer.createContainer(/* root: */ null);
Renderer.updateContainer(
<a><b /></a>,
container,
/* parentComponent: */ null,
/* callback: */ null,
);
expect(creates).toBe(2);
});
});

Просмотреть файл

@ -11,17 +11,17 @@
'use strict';
var PropTypes;
var React;
var ReactNoop;
var ReactFeatureFlags;
var PropTypes;
describe('ReactIncremental', () => {
beforeEach(() => {
jest.resetModules();
PropTypes = require('prop-types');
React = require('react');
ReactNoop = require('ReactNoop');
PropTypes = require('prop-types');
ReactFeatureFlags = require('ReactFeatureFlags');
ReactFeatureFlags.disableNewFiberFeatures = false;
@ -51,10 +51,10 @@ describe('ReactIncremental', () => {
var fooCalled = false;
function Foo() {
fooCalled = true;
return [<Bar isBar={true} />, <Bar isBar={true} />];
return [<Bar key="a" isBar={true} />, <Bar key="b" isBar={true} />];
}
ReactNoop.render(<Foo />, () => renderCallbackCalled = true);
ReactNoop.render(<Foo />, () => (renderCallbackCalled = true));
expect(fooCalled).toBe(false);
expect(barCalled).toBe(false);
expect(renderCallbackCalled).toBe(false);
@ -103,7 +103,8 @@ describe('ReactIncremental', () => {
}
ReactNoop.render(<Foo text="foo" />, () =>
ops.push('renderCallbackCalled'));
ops.push('renderCallbackCalled'),
);
ReactNoop.flush();
expect(ops).toEqual([
@ -117,9 +118,11 @@ describe('ReactIncremental', () => {
ops = [];
ReactNoop.render(<Foo text="bar" />, () =>
ops.push('firstRenderCallbackCalled'));
ops.push('firstRenderCallbackCalled'),
);
ReactNoop.render(<Foo text="bar" />, () =>
ops.push('secondRenderCallbackCalled'));
ops.push('secondRenderCallbackCalled'),
);
ReactNoop.flush();
// TODO: Test bail out of host components. This is currently unobservable.
@ -384,8 +387,8 @@ describe('ReactIncremental', () => {
}
render() {
return [
<Tester unused={this.props.unused} />,
<bbb hidden={true}>
<Tester key="a" unused={this.props.unused} />,
<bbb key="b" hidden={true}>
<ccc>
<Middle>Hi</Middle>
</ccc>
@ -449,6 +452,47 @@ describe('ReactIncremental', () => {
expect(ops).toEqual(['Foo', 'Bar', 'Bar']);
});
it('can resume mounting a class component', () => {
let ops = [];
let foo;
class Parent extends React.Component {
shouldComponentUpdate() {
return false;
}
render() {
return <Foo prop={this.props.prop} />;
}
}
class Foo extends React.Component {
constructor(props) {
super(props);
// Test based on a www bug where props was null on resume
ops.push('Foo constructor: ' + props.prop);
}
render() {
foo = this;
ops.push('Foo');
return <Bar />;
}
}
function Bar() {
ops.push('Bar');
return <div />;
}
ReactNoop.render(<Parent prop="foo" />);
ReactNoop.flushDeferredPri(20);
expect(ops).toEqual(['Foo constructor: foo', 'Foo']);
foo.setState({value: 'bar'});
ops = [];
ReactNoop.flush();
expect(ops).toEqual(['Foo constructor: foo', 'Foo', 'Bar']);
});
it('can reuse work done after being preempted', () => {
var ops = [];
@ -583,8 +627,8 @@ describe('ReactIncremental', () => {
// low priority. I think this would be fixed by changing
// pendingWorkPriority and progressedPriority to be the priority of
// the children only, not including the fiber itself.
<div><Child /></div>,
<Sibling />,
<div key="a"><Child /></div>,
<Sibling key="b" />,
];
}
@ -875,15 +919,13 @@ describe('ReactIncremental', () => {
it('can replaceState', () => {
let instance;
const Bar = React.createClass({
getInitialState() {
instance = this;
return {a: 'a'};
},
class Bar extends React.Component {
state = {a: 'a'};
render() {
instance = this;
return <div>{this.props.children}</div>;
},
});
}
}
function Foo() {
return (
@ -897,7 +939,7 @@ describe('ReactIncremental', () => {
ReactNoop.flush();
instance.setState({b: 'b'});
instance.setState({c: 'c'});
instance.replaceState({d: 'd'});
instance.updater.enqueueReplaceState(instance, {d: 'd'});
ReactNoop.flush();
expect(instance.state).toEqual({d: 'd'});
});
@ -1415,7 +1457,7 @@ describe('ReactIncremental', () => {
}
function App(props) {
return [<LifeCycle x={props.x} />, <Sibling />];
return [<LifeCycle key="a" x={props.x} />, <Sibling key="b" />];
}
ReactNoop.render(<App x={0} />);
@ -1664,13 +1706,13 @@ describe('ReactIncremental', () => {
render() {
ops.push('Indirection ' + JSON.stringify(this.context));
return [
<ShowLocale />,
<ShowRoute />,
<ShowNeither />,
<Intl locale="ru">
<ShowLocale key="a" />,
<ShowRoute key="b" />,
<ShowNeither key="c" />,
<Intl key="d" locale="ru">
<ShowBoth />
</Intl>,
<ShowBoth />,
<ShowBoth key="e" />,
];
}
}

Просмотреть файл

@ -11,6 +11,7 @@
'use strict';
var PropTypes;
var React;
var ReactNoop;
var ReactFeatureFlags;
@ -18,6 +19,7 @@ var ReactFeatureFlags;
describe('ReactIncrementalErrorHandling', () => {
beforeEach(() => {
jest.resetModules();
PropTypes = require('prop-types');
React = require('react');
ReactNoop = require('ReactNoop');
ReactFeatureFlags = require('ReactFeatureFlags');
@ -25,7 +27,7 @@ describe('ReactIncrementalErrorHandling', () => {
});
function div(...children) {
children = children.map(c => typeof c === 'string' ? {text: c} : c);
children = children.map(c => (typeof c === 'string' ? {text: c} : c));
return {type: 'div', children, prop: undefined};
}

Просмотреть файл

@ -12,12 +12,12 @@
'use strict';
describe('ReactDebugFiberPerf', () => {
let PropTypes;
let React;
let ReactCoroutine;
let ReactFeatureFlags;
let ReactNoop;
let ReactPortal;
let PropTypes;
let root;
let activeMeasure;
@ -71,12 +71,14 @@ describe('ReactDebugFiberPerf', () => {
label: null,
parent: activeMeasure,
toString() {
return [
' '.repeat(this.indent) + this.label,
...this.children.map(c => c.toString()),
].join('\n') +
return (
[
' '.repeat(this.indent) + this.label,
...this.children.map(c => c.toString()),
].join('\n') +
// Extra newline after each root reconciliation
(this.indent === 0 ? '\n' : '');
(this.indent === 0 ? '\n' : '')
);
},
};
// Step one level deeper
@ -114,13 +116,13 @@ describe('ReactDebugFiberPerf', () => {
global.performance = createUserTimingPolyfill();
// Import after the polyfill is set up:
PropTypes = require('prop-types');
React = require('React');
ReactCoroutine = require('ReactCoroutine');
ReactFeatureFlags = require('ReactFeatureFlags');
ReactNoop = require('ReactNoop');
ReactPortal = require('ReactPortal');
ReactFeatureFlags.disableNewFiberFeatures = false;
PropTypes = require('prop-types');
});
afterEach(() => {
@ -170,11 +172,11 @@ describe('ReactDebugFiberPerf', () => {
<Parent>
<Parent>
<Parent>
<A ref={inst => a = inst} />
<A ref={inst => (a = inst)} />
</Parent>
</Parent>
<Parent>
<B ref={inst => b = inst} />
<B ref={inst => (b = inst)} />
</Parent>
</Parent>,
);
@ -449,12 +451,12 @@ describe('ReactDebugFiberPerf', () => {
}
function Indirection() {
return [<CoChild bar={true} />, <CoChild bar={false} />];
return [<CoChild key="a" bar={true} />, <CoChild key="b" bar={false} />];
}
function HandleYields(props, yields) {
return yields.map(y => (
<y.continuation isSame={props.foo === y.props.bar} />
return yields.map((y, i) => (
<y.continuation key={i} isSame={props.foo === y.props.bar} />
));
}

Просмотреть файл

@ -29,18 +29,23 @@ describe('ReactIncrementalReflection', () => {
const instances = [];
const Component = React.createClass({
class Component extends React.Component {
_isMounted() {
// No longer a public API, but we can test that it works internally by
// reaching into the updater.
return this.updater.isMounted(this);
}
componentWillMount() {
instances.push(this);
ops.push('componentWillMount', this.isMounted());
},
ops.push('componentWillMount', this._isMounted());
}
componentDidMount() {
ops.push('componentDidMount', this.isMounted());
},
ops.push('componentDidMount', this._isMounted());
}
render() {
return <span />;
},
});
}
}
function Foo() {
return <Component />;
@ -53,7 +58,7 @@ describe('ReactIncrementalReflection', () => {
expect(ops).toEqual(['componentWillMount', false]);
expect(instances[0].isMounted()).toBe(false);
expect(instances[0]._isMounted()).toBe(false);
ops = [];
@ -62,7 +67,7 @@ describe('ReactIncrementalReflection', () => {
expect(ops).toEqual(['componentDidMount', true]);
expect(instances[0].isMounted()).toBe(true);
expect(instances[0]._isMounted()).toBe(true);
});
it('handles isMounted when an unmount is deferred', () => {
@ -70,18 +75,21 @@ describe('ReactIncrementalReflection', () => {
const instances = [];
const Component = React.createClass({
class Component extends React.Component {
_isMounted() {
return this.updater.isMounted(this);
}
componentWillMount() {
instances.push(this);
},
}
componentWillUnmount() {
ops.push('componentWillUnmount', this.isMounted());
},
ops.push('componentWillUnmount', this._isMounted());
}
render() {
ops.push('Component');
return <span />;
},
});
}
}
function Other() {
ops.push('Other');
@ -98,7 +106,7 @@ describe('ReactIncrementalReflection', () => {
expect(ops).toEqual(['Component']);
ops = [];
expect(instances[0].isMounted()).toBe(true);
expect(instances[0]._isMounted()).toBe(true);
ReactNoop.render(<Foo mount={false} />);
// Render part way through but don't yet commit the updates so it is not
@ -108,14 +116,14 @@ describe('ReactIncrementalReflection', () => {
expect(ops).toEqual(['Other']);
ops = [];
expect(instances[0].isMounted()).toBe(true);
expect(instances[0]._isMounted()).toBe(true);
// Finish flushing the unmount.
ReactNoop.flush();
expect(ops).toEqual(['componentWillUnmount', true]);
expect(instances[0].isMounted()).toBe(false);
expect(instances[0]._isMounted()).toBe(false);
});
it('finds no node before insertion and correct node before deletion', () => {
@ -143,13 +151,13 @@ describe('ReactIncrementalReflection', () => {
render() {
ops.push('render');
return this.props.step < 2
? <span ref={ref => this.span = ref} />
? <span ref={ref => (this.span = ref)} />
: this.props.step === 2
? <div ref={ref => this.div = ref} />
? <div ref={ref => (this.div = ref)} />
: this.props.step === 3
? null
: this.props.step === 4
? <div ref={ref => this.span = ref} />
? <div ref={ref => (this.span = ref)} />
: null;
}
}
@ -161,7 +169,7 @@ describe('ReactIncrementalReflection', () => {
}
function Foo(props) {
return [<Component step={props.step} />, <Sibling />];
return [<Component key="a" step={props.step} />, <Sibling key="b" />];
}
ReactNoop.render(<Foo step={0} />);

Просмотреть файл

@ -29,7 +29,7 @@ describe('ReactIncrementalSideEffects', () => {
}
function div(...children) {
children = children.map(c => typeof c === 'string' ? {text: c} : c);
children = children.map(c => (typeof c === 'string' ? {text: c} : c));
return {type: 'div', children, prop: undefined};
}
@ -565,7 +565,10 @@ describe('ReactIncrementalSideEffects', () => {
}
render() {
ops.push('Baz');
return [<Bar idx={this.props.idx} />, <Bar idx={this.props.idx} />];
return [
<Bar key="a" idx={this.props.idx} />,
<Bar key="b" idx={this.props.idx} />,
];
}
}
function Foo(props) {

Просмотреть файл

@ -74,22 +74,20 @@ describe('ReactIncrementalUpdates', () => {
it('only drops updates with equal or lesser priority when replaceState is called', () => {
let instance;
let ops = [];
const Foo = React.createClass({
getInitialState() {
return {};
},
class Foo extends React.Component {
state = {};
componentDidMount() {
ops.push('componentDidMount');
},
}
componentDidUpdate() {
ops.push('componentDidUpdate');
},
}
render() {
ops.push('render');
instance = this;
return <div />;
},
});
}
}
ReactNoop.render(<Foo />);
ReactNoop.flush();
@ -100,7 +98,7 @@ describe('ReactIncrementalUpdates', () => {
instance.setState({a: 'a'});
instance.setState({b: 'b'});
});
instance.replaceState({c: 'c'});
instance.updater.enqueueReplaceState(instance, {c: 'c'});
instance.setState({d: 'd'});
ReactNoop.flushAnimationPri();
@ -201,19 +199,17 @@ describe('ReactIncrementalUpdates', () => {
it('can abort an update, schedule a replaceState, and resume', () => {
let instance;
let ops = [];
const Foo = React.createClass({
getInitialState() {
return {};
},
class Foo extends React.Component {
state = {};
componentDidUpdate() {
ops.push('componentDidUpdate');
},
}
render() {
ops.push('render');
instance = this;
return <span />;
},
});
}
}
ReactNoop.render(<Foo />);
ReactNoop.flush();
@ -245,7 +241,9 @@ describe('ReactIncrementalUpdates', () => {
instance.setState(createUpdate('f'));
ReactNoop.performAnimationWork(() => {
instance.setState(createUpdate('d'));
instance.replaceState(createUpdate('e'));
// No longer a public API, but we can test that it works internally by
// reaching into the updater.
instance.updater.enqueueReplaceState(instance, createUpdate('e'));
});
instance.setState(createUpdate('g'));
@ -256,21 +254,23 @@ describe('ReactIncrementalUpdates', () => {
it('passes accumulation of previous updates to replaceState updater function', () => {
let instance;
const Foo = React.createClass({
getInitialState() {
return {};
},
class Foo extends React.Component {
state = {};
render() {
instance = this;
return <span />;
},
});
}
}
ReactNoop.render(<Foo />);
ReactNoop.flush();
instance.setState({a: 'a'});
instance.setState({b: 'b'});
instance.replaceState(previousState => ({previousState}));
// No longer a public API, but we can test that it works internally by
// reaching into the updater.
instance.updater.enqueueReplaceState(instance, previousState => ({
previousState,
}));
ReactNoop.flush();
expect(instance.state).toEqual({previousState: {a: 'a', b: 'b'}});
});

Просмотреть файл

@ -77,7 +77,7 @@ describe('ReactTopLevelFragment', function() {
function Fragment({condition}) {
return condition
? <Stateful key="a" />
: [[<Stateful key="a" />, <div key="b">World</div>], <div />];
: [[<Stateful key="a" />, <div key="b">World</div>], <div key="c" />];
}
ReactNoop.render(<Fragment />);
ReactNoop.flush();
@ -106,8 +106,8 @@ describe('ReactTopLevelFragment', function() {
function Fragment({condition}) {
return condition
? [null, <Stateful />]
: [<div>Hello</div>, <Stateful />];
? [null, <Stateful key="a" />]
: [<div key="b">Hello</div>, <Stateful key="a" />];
}
ReactNoop.render(<Fragment />);
ReactNoop.flush();
@ -144,7 +144,7 @@ describe('ReactTopLevelFragment', function() {
function Fragment({condition}) {
return condition
? [[<div key="b">World</div>, <Stateful key="a" />]]
: [[<Stateful key="a" />, <div key="b">World</div>], <div />];
: [[<Stateful key="a" />, <div key="b">World</div>], <div key="c" />];
}
ReactNoop.render(<Fragment />);
ReactNoop.flush();

Просмотреть файл

@ -88,18 +88,22 @@ exports.createYield = function(value: mixed): ReactYield {
* Verifies the object is a coroutine object.
*/
exports.isCoroutine = function(object: mixed): boolean {
return typeof object === 'object' &&
return (
typeof object === 'object' &&
object !== null &&
object.$$typeof === REACT_COROUTINE_TYPE;
object.$$typeof === REACT_COROUTINE_TYPE
);
};
/**
* Verifies the object is a yield object.
*/
exports.isYield = function(object: mixed): boolean {
return typeof object === 'object' &&
return (
typeof object === 'object' &&
object !== null &&
object.$$typeof === REACT_YIELD_TYPE;
object.$$typeof === REACT_YIELD_TYPE
);
};
exports.REACT_YIELD_TYPE = REACT_YIELD_TYPE;

Просмотреть файл

@ -16,9 +16,8 @@ import type {ReactNodeList} from 'ReactTypes';
// The Symbol used to tag the special React types. If there is no native Symbol
// nor polyfill, then a plain number is used for performance.
var REACT_PORTAL_TYPE = (typeof Symbol === 'function' &&
Symbol.for &&
Symbol.for('react.portal')) ||
var REACT_PORTAL_TYPE =
(typeof Symbol === 'function' && Symbol.for && Symbol.for('react.portal')) ||
0xeaca;
export type ReactPortal = {
@ -51,9 +50,11 @@ exports.createPortal = function(
* Verifies the object is a portal object.
*/
exports.isPortal = function(object: mixed): boolean {
return typeof object === 'object' &&
return (
typeof object === 'object' &&
object !== null &&
object.$$typeof === REACT_PORTAL_TYPE;
object.$$typeof === REACT_PORTAL_TYPE
);
};
exports.REACT_PORTAL_TYPE = REACT_PORTAL_TYPE;

Просмотреть файл

@ -14,18 +14,16 @@
import type {DebugID} from 'ReactInstanceType';
export type Operation =
& {instanceID: DebugID}
& (
| {type: 'mount', payload: string}
| {type: 'insert child', payload: {toIndex: number, content: string}}
| {type: 'move child', payload: {fromIndex: number, toIndex: number}}
| {type: 'replace children', payload: string}
| {type: 'replace text', payload: string}
| {type: 'replace with', payload: string}
| {type: 'update styles', payload: mixed /* Style Object */}
| {type: 'update attribute', payload: {[name: string]: string}}
| {type: 'remove attribute', payload: string});
export type Operation = {instanceID: DebugID} & (
| {type: 'mount', payload: string}
| {type: 'insert child', payload: {toIndex: number, content: string}}
| {type: 'move child', payload: {fromIndex: number, toIndex: number}}
| {type: 'replace children', payload: string}
| {type: 'replace text', payload: string}
| {type: 'replace with', payload: string}
| {type: 'update styles', payload: mixed /* Style Object */}
| {type: 'update attribute', payload: {[name: string]: string}}
| {type: 'remove attribute', payload: string});
// Trust the developer to only use this with a __DEV__ check
var ReactHostOperationHistoryHook = ((null: any): typeof ReactHostOperationHistoryHook);

Просмотреть файл

@ -0,0 +1,103 @@
/**
* Copyright 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule BrowserEventConstants
*/
'use strict';
var getVendorPrefixedEventName = require('getVendorPrefixedEventName');
/**
* Types of raw signals from the browser caught at the top level.
*
* For events like 'submit' which don't consistently bubble (which we
* trap at a lower node than `document`), binding at `document` would
* cause duplicate events so we don't include them here.
*/
var topLevelTypes = {
topAbort: 'abort',
topAnimationEnd: getVendorPrefixedEventName('animationend') || 'animationend',
topAnimationIteration: getVendorPrefixedEventName('animationiteration') ||
'animationiteration',
topAnimationStart: getVendorPrefixedEventName('animationstart') ||
'animationstart',
topBlur: 'blur',
topCancel: 'cancel',
topCanPlay: 'canplay',
topCanPlayThrough: 'canplaythrough',
topChange: 'change',
topClick: 'click',
topClose: 'close',
topCompositionEnd: 'compositionend',
topCompositionStart: 'compositionstart',
topCompositionUpdate: 'compositionupdate',
topContextMenu: 'contextmenu',
topCopy: 'copy',
topCut: 'cut',
topDoubleClick: 'dblclick',
topDrag: 'drag',
topDragEnd: 'dragend',
topDragEnter: 'dragenter',
topDragExit: 'dragexit',
topDragLeave: 'dragleave',
topDragOver: 'dragover',
topDragStart: 'dragstart',
topDrop: 'drop',
topDurationChange: 'durationchange',
topEmptied: 'emptied',
topEncrypted: 'encrypted',
topEnded: 'ended',
topError: 'error',
topFocus: 'focus',
topInput: 'input',
topKeyDown: 'keydown',
topKeyPress: 'keypress',
topKeyUp: 'keyup',
topLoadedData: 'loadeddata',
topLoad: 'load',
topLoadedMetadata: 'loadedmetadata',
topLoadStart: 'loadstart',
topMouseDown: 'mousedown',
topMouseMove: 'mousemove',
topMouseOut: 'mouseout',
topMouseOver: 'mouseover',
topMouseUp: 'mouseup',
topPaste: 'paste',
topPause: 'pause',
topPlay: 'play',
topPlaying: 'playing',
topProgress: 'progress',
topRateChange: 'ratechange',
topScroll: 'scroll',
topSeeked: 'seeked',
topSeeking: 'seeking',
topSelectionChange: 'selectionchange',
topStalled: 'stalled',
topSuspend: 'suspend',
topTextInput: 'textInput',
topTimeUpdate: 'timeupdate',
topToggle: 'toggle',
topTouchCancel: 'touchcancel',
topTouchEnd: 'touchend',
topTouchMove: 'touchmove',
topTouchStart: 'touchstart',
topTransitionEnd: getVendorPrefixedEventName('transitionend') ||
'transitionend',
topVolumeChange: 'volumechange',
topWaiting: 'waiting',
topWheel: 'wheel',
};
export type TopLevelTypes = $Enum<typeof topLevelTypes>;
var BrowserEventConstants = {
topLevelTypes,
};
module.exports = BrowserEventConstants;

Просмотреть файл

@ -1,99 +0,0 @@
/**
* Copyright 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule EventConstants
*/
'use strict';
export type PropagationPhases = 'bubbled' | 'captured';
/**
* Types of raw signals from the browser caught at the top level.
*/
var topLevelTypes = {
topAbort: null,
topAnimationEnd: null,
topAnimationIteration: null,
topAnimationStart: null,
topBlur: null,
topCancel: null,
topCanPlay: null,
topCanPlayThrough: null,
topChange: null,
topClick: null,
topClose: null,
topCompositionEnd: null,
topCompositionStart: null,
topCompositionUpdate: null,
topContextMenu: null,
topCopy: null,
topCut: null,
topDoubleClick: null,
topDrag: null,
topDragEnd: null,
topDragEnter: null,
topDragExit: null,
topDragLeave: null,
topDragOver: null,
topDragStart: null,
topDrop: null,
topDurationChange: null,
topEmptied: null,
topEncrypted: null,
topEnded: null,
topError: null,
topFocus: null,
topInput: null,
topInvalid: null,
topKeyDown: null,
topKeyPress: null,
topKeyUp: null,
topLoad: null,
topLoadedData: null,
topLoadedMetadata: null,
topLoadStart: null,
topMouseDown: null,
topMouseMove: null,
topMouseOut: null,
topMouseOver: null,
topMouseUp: null,
topPaste: null,
topPause: null,
topPlay: null,
topPlaying: null,
topProgress: null,
topRateChange: null,
topReset: null,
topScroll: null,
topSeeked: null,
topSeeking: null,
topSelectionChange: null,
topStalled: null,
topSubmit: null,
topSuspend: null,
topTextInput: null,
topTimeUpdate: null,
topToggle: null,
topTouchCancel: null,
topTouchEnd: null,
topTouchMove: null,
topTouchStart: null,
topTransitionEnd: null,
topVolumeChange: null,
topWaiting: null,
topWheel: null,
};
export type TopLevelTypes = $Enum<typeof topLevelTypes>;
var EventConstants = {
topLevelTypes,
};
module.exports = EventConstants;

Просмотреть файл

@ -49,10 +49,12 @@ var executeDispatchesAndReleaseTopLevel = function(e) {
};
function isInteractive(tag) {
return tag === 'button' ||
return (
tag === 'button' ||
tag === 'input' ||
tag === 'select' ||
tag === 'textarea';
tag === 'textarea'
);
}
function shouldPreventMouseEvent(name, type, props) {
@ -140,7 +142,8 @@ var EventPluginHub = {
} else {
const currentElement = inst._currentElement;
if (
typeof currentElement === 'string' || typeof currentElement === 'number'
typeof currentElement === 'string' ||
typeof currentElement === 'number'
) {
// Text node, let it bubble through.
return null;

Просмотреть файл

@ -141,9 +141,8 @@ function publishRegistrationName(
registrationName,
);
EventPluginRegistry.registrationNameModules[registrationName] = pluginModule;
EventPluginRegistry.registrationNameDependencies[
registrationName
] = pluginModule.eventTypes[eventName].dependencies;
EventPluginRegistry.registrationNameDependencies[registrationName] =
pluginModule.eventTypes[eventName].dependencies;
if (__DEV__) {
var lowerCasedName = registrationName.toLowerCase();

Просмотреть файл

@ -41,9 +41,11 @@ var injection = {
};
function isEndish(topLevelType) {
return topLevelType === 'topMouseUp' ||
return (
topLevelType === 'topMouseUp' ||
topLevelType === 'topTouchEnd' ||
topLevelType === 'topTouchCancel';
topLevelType === 'topTouchCancel'
);
}
function isMoveish(topLevelType) {

Просмотреть файл

@ -18,7 +18,7 @@ var accumulateInto = require('accumulateInto');
var forEachAccumulated = require('forEachAccumulated');
var warning = require('fbjs/lib/warning');
import type {PropagationPhases} from 'EventConstants';
type PropagationPhases = 'bubbled' | 'captured';
var getListener = EventPluginHub.getListener;
@ -27,9 +27,8 @@ var getListener = EventPluginHub.getListener;
* "phases" of propagation. This finds listeners by a given phase.
*/
function listenerAtPhase(inst, event, propagationPhase: PropagationPhases) {
var registrationName = event.dispatchConfig.phasedRegistrationNames[
propagationPhase
];
var registrationName =
event.dispatchConfig.phasedRegistrationNames[propagationPhase];
return getListener(inst, registrationName);
}

Просмотреть файл

@ -25,14 +25,12 @@ export type DispatchConfig = {
registrationName?: string,
};
export type ReactSyntheticEvent =
& {
export type ReactSyntheticEvent = {
dispatchConfig: DispatchConfig,
getPooled: (
dispatchConfig: DispatchConfig,
getPooled: (
dispatchConfig: DispatchConfig,
targetInst: ReactInstance,
nativeTarget: Event,
nativeEventTarget: EventTarget,
) => ReactSyntheticEvent,
}
& SyntheticEvent;
targetInst: ReactInstance,
nativeTarget: Event,
nativeEventTarget: EventTarget,
) => ReactSyntheticEvent,
} & SyntheticEvent;

Просмотреть файл

@ -24,7 +24,8 @@ var isMoveish = EventPluginUtils.isMoveish;
var isEndish = EventPluginUtils.isEndish;
var executeDirectDispatch = EventPluginUtils.executeDirectDispatch;
var hasDispatches = EventPluginUtils.hasDispatches;
var executeDispatchesInOrderStopAtTrue = EventPluginUtils.executeDispatchesInOrderStopAtTrue;
var executeDispatchesInOrderStopAtTrue =
EventPluginUtils.executeDispatchesInOrderStopAtTrue;
/**
* Instance of element that should respond to touch/move types of interactions,
@ -375,9 +376,11 @@ function setResponderAndExtractTransfer(
nativeEvent,
nativeEventTarget,
);
terminationRequestEvent.touchHistory = ResponderTouchHistoryStore.touchHistory;
terminationRequestEvent.touchHistory =
ResponderTouchHistoryStore.touchHistory;
EventPropagators.accumulateDirectDispatches(terminationRequestEvent);
var shouldSwitch = !hasDispatches(terminationRequestEvent) ||
var shouldSwitch =
!hasDispatches(terminationRequestEvent) ||
executeDirectDispatch(terminationRequestEvent);
if (!terminationRequestEvent.isPersistent()) {
terminationRequestEvent.constructor.release(terminationRequestEvent);
@ -417,18 +420,20 @@ function setResponderAndExtractTransfer(
* element to claim responder status. Any start event could trigger a transfer
* of responderInst. Any move event could trigger a transfer.
*
* @param {string} topLevelType Record from `EventConstants`.
* @param {string} topLevelType Record from `BrowserEventConstants`.
* @return {boolean} True if a transfer of responder could possibly occur.
*/
function canTriggerTransfer(topLevelType, topLevelInst, nativeEvent) {
return topLevelInst &&
return (
topLevelInst &&
// responderIgnoreScroll: We are trying to migrate away from specifically
// tracking native scroll events here and responderIgnoreScroll indicates we
// will send topTouchCancel to handle canceling touch events instead
((topLevelType === 'topScroll' && !nativeEvent.responderIgnoreScroll) ||
(trackedTouchCount > 0 && topLevelType === 'topSelectionChange') ||
isStartish(topLevelType) ||
isMoveish(topLevelType));
isMoveish(topLevelType))
);
}
/**
@ -530,9 +535,10 @@ var ResponderEventPlugin = {
extracted = accumulate(extracted, gesture);
}
var isResponderTerminate = responderInst &&
topLevelType === 'topTouchCancel';
var isResponderRelease = responderInst &&
var isResponderTerminate =
responderInst && topLevelType === 'topTouchCancel';
var isResponderRelease =
responderInst &&
!isResponderTerminate &&
isEndish(topLevelType) &&
noResponderTouches(nativeEvent);
@ -552,7 +558,8 @@ var ResponderEventPlugin = {
changeResponder(null);
}
var numberActiveTouches = ResponderTouchHistoryStore.touchHistory.numberActiveTouches;
var numberActiveTouches =
ResponderTouchHistoryStore.touchHistory.numberActiveTouches;
if (
ResponderEventPlugin.GlobalInteractionHandler &&
numberActiveTouches !== previousActiveTouches

Просмотреть файл

@ -17,11 +17,7 @@ const EventPluginUtils = require('EventPluginUtils');
const invariant = require('fbjs/lib/invariant');
const warning = require('fbjs/lib/warning');
const {
isEndish,
isMoveish,
isStartish,
} = EventPluginUtils;
const {isEndish, isMoveish, isStartish} = EventPluginUtils;
/**
* Tracks the position and time of each active touch by `touch.identifier`. We
@ -193,9 +189,8 @@ const ResponderTouchHistoryStore = {
nativeEvent.changedTouches.forEach(recordTouchStart);
touchHistory.numberActiveTouches = nativeEvent.touches.length;
if (touchHistory.numberActiveTouches === 1) {
touchHistory.indexOfSingleActiveTouch = nativeEvent.touches[
0
].identifier;
touchHistory.indexOfSingleActiveTouch =
nativeEvent.touches[0].identifier;
}
} else if (isEndish(topLevelType)) {
nativeEvent.changedTouches.forEach(recordTouchEnd);

Просмотреть файл

@ -256,15 +256,13 @@ var registerTestHandlers = function(eventTestConfig, readableIDToID) {
var hasTwoPhase = !!oneEventTypeTestConfig.bubbled;
if (hasTwoPhase) {
registerOneEventType(
ResponderEventPlugin.eventTypes[
eventName
].phasedRegistrationNames.bubbled,
ResponderEventPlugin.eventTypes[eventName].phasedRegistrationNames
.bubbled,
oneEventTypeTestConfig.bubbled,
);
registerOneEventType(
ResponderEventPlugin.eventTypes[
eventName
].phasedRegistrationNames.captured,
ResponderEventPlugin.eventTypes[eventName].phasedRegistrationNames
.captured,
oneEventTypeTestConfig.captured,
);
} else {

Просмотреть файл

@ -0,0 +1,101 @@
/**
* Copyright 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule getVendorPrefixedEventName
*/
'use strict';
var ExecutionEnvironment = require('fbjs/lib/ExecutionEnvironment');
/**
* Generate a mapping of standard vendor prefixes using the defined style property and event name.
*
* @param {string} styleProp
* @param {string} eventName
* @returns {object}
*/
function makePrefixMap(styleProp, eventName) {
var prefixes = {};
prefixes[styleProp.toLowerCase()] = eventName.toLowerCase();
prefixes['Webkit' + styleProp] = 'webkit' + eventName;
prefixes['Moz' + styleProp] = 'moz' + eventName;
prefixes['ms' + styleProp] = 'MS' + eventName;
prefixes['O' + styleProp] = 'o' + eventName.toLowerCase();
return prefixes;
}
/**
* A list of event names to a configurable list of vendor prefixes.
*/
var vendorPrefixes = {
animationend: makePrefixMap('Animation', 'AnimationEnd'),
animationiteration: makePrefixMap('Animation', 'AnimationIteration'),
animationstart: makePrefixMap('Animation', 'AnimationStart'),
transitionend: makePrefixMap('Transition', 'TransitionEnd'),
};
/**
* Event names that have already been detected and prefixed (if applicable).
*/
var prefixedEventNames = {};
/**
* Element to check for prefixes on.
*/
var style = {};
/**
* Bootstrap if a DOM exists.
*/
if (ExecutionEnvironment.canUseDOM) {
style = document.createElement('div').style;
// On some platforms, in particular some releases of Android 4.x,
// the un-prefixed "animation" and "transition" properties are defined on the
// style object but the events that fire will still be prefixed, so we need
// to check if the un-prefixed events are usable, and if not remove them from the map.
if (!('AnimationEvent' in window)) {
delete vendorPrefixes.animationend.animation;
delete vendorPrefixes.animationiteration.animation;
delete vendorPrefixes.animationstart.animation;
}
// Same as above
if (!('TransitionEvent' in window)) {
delete vendorPrefixes.transitionend.transition;
}
}
/**
* Attempts to determine the correct vendor prefixed event name.
*
* @param {string} eventName
* @returns {string}
*/
function getVendorPrefixedEventName(eventName) {
if (prefixedEventNames[eventName]) {
return prefixedEventNames[eventName];
} else if (!vendorPrefixes[eventName]) {
return eventName;
}
var prefixMap = vendorPrefixes[eventName];
for (var styleProp in prefixMap) {
if (prefixMap.hasOwnProperty(styleProp) && styleProp in style) {
return (prefixedEventNames[eventName] = prefixMap[styleProp]);
}
}
return '';
}
module.exports = getVendorPrefixedEventName;

Просмотреть файл

@ -34,9 +34,11 @@ function shouldUpdateReactComponent(prevElement, nextElement) {
if (prevType === 'string' || prevType === 'number') {
return nextType === 'string' || nextType === 'number';
} else {
return nextType === 'object' &&
return (
nextType === 'object' &&
prevElement.type === nextElement.type &&
prevElement.key === nextElement.key;
prevElement.key === nextElement.key
);
}
}

Просмотреть файл

@ -17,7 +17,7 @@ var ReactReconciler = require('ReactReconciler');
var instantiateReactComponent = require('instantiateReactComponent');
var shouldUpdateReactComponent = require('shouldUpdateReactComponent');
var traverseAllChildren = require('traverseAllChildren');
var traverseStackChildren = require('traverseStackChildren');
var warning = require('fbjs/lib/warning');
var ReactComponentTreeHook;
@ -32,7 +32,8 @@ if (
// https://github.com/facebook/react/issues/7240
// Remove the inline requires when we don't need them anymore:
// https://github.com/facebook/react/pull/7178
ReactComponentTreeHook = require('react/lib/ReactComponentTreeHook');
ReactComponentTreeHook = require('ReactGlobalSharedState')
.ReactComponentTreeHook;
}
function instantiateChild(childInstances, child, name, selfDebugID) {
@ -40,7 +41,8 @@ function instantiateChild(childInstances, child, name, selfDebugID) {
var keyUnique = childInstances[name] === undefined;
if (__DEV__) {
if (!ReactComponentTreeHook) {
ReactComponentTreeHook = require('react/lib/ReactComponentTreeHook');
ReactComponentTreeHook = require('ReactGlobalSharedState')
.ReactComponentTreeHook;
}
if (!keyUnique) {
warning(
@ -84,14 +86,14 @@ var ReactChildReconciler = {
var childInstances = {};
if (__DEV__) {
traverseAllChildren(
traverseStackChildren(
nestedChildNodes,
(childInsts, child, name) =>
instantiateChild(childInsts, child, name, selfDebugID),
childInstances,
);
} else {
traverseAllChildren(nestedChildNodes, instantiateChild, childInstances);
traverseStackChildren(nestedChildNodes, instantiateChild, childInstances);
}
return childInstances;
},
@ -147,7 +149,8 @@ var ReactChildReconciler = {
nextChildren[name] = prevChild;
} else {
if (
!ReactFeatureFlags.prepareNewChildrenBeforeUnmountInStack && prevChild
!ReactFeatureFlags.prepareNewChildrenBeforeUnmountInStack &&
prevChild
) {
removedNodes[name] = ReactReconciler.getHostNode(prevChild);
ReactReconciler.unmountComponent(
@ -171,7 +174,8 @@ var ReactChildReconciler = {
);
mountImages.push(nextChildMountImage);
if (
ReactFeatureFlags.prepareNewChildrenBeforeUnmountInStack && prevChild
ReactFeatureFlags.prepareNewChildrenBeforeUnmountInStack &&
prevChild
) {
removedNodes[name] = ReactReconciler.getHostNode(prevChild);
ReactReconciler.unmountComponent(

Просмотреть файл

@ -43,8 +43,10 @@ var ReactComponentEnvironment = {
!injected,
'ReactCompositeComponent: injectEnvironment() can only be called once.',
);
ReactComponentEnvironment.replaceNodeWithMarkup = environment.replaceNodeWithMarkup;
ReactComponentEnvironment.processChildrenUpdates = environment.processChildrenUpdates;
ReactComponentEnvironment.replaceNodeWithMarkup =
environment.replaceNodeWithMarkup;
ReactComponentEnvironment.processChildrenUpdates =
environment.processChildrenUpdates;
injected = true;
},
},

Просмотреть файл

@ -14,20 +14,20 @@
var React = require('react');
var ReactComponentEnvironment = require('ReactComponentEnvironment');
var ReactCompositeComponentTypes = require('ReactCompositeComponentTypes');
var ReactCurrentOwner = require('react/lib/ReactCurrentOwner');
var ReactErrorUtils = require('ReactErrorUtils');
var ReactFeatureFlags = require('ReactFeatureFlags');
var ReactInstanceMap = require('ReactInstanceMap');
var ReactInstrumentation = require('ReactInstrumentation');
var ReactNodeTypes = require('ReactNodeTypes');
var ReactReconciler = require('ReactReconciler');
var {ReactCurrentOwner} = require('ReactGlobalSharedState');
if (__DEV__) {
var checkReactTypeSpec = require('checkReactTypeSpec');
var ReactDebugCurrentFrame = require('react/lib/ReactDebugCurrentFrame');
var {ReactDebugCurrentFrame} = require('ReactGlobalSharedState');
var warningAboutMissingGetChildContext = {};
}
var checkPropTypes = require('prop-types/checkPropTypes');
var emptyObject = require('fbjs/lib/emptyObject');
var invariant = require('fbjs/lib/invariant');
var shallowEqual = require('fbjs/lib/shallowEqual');
@ -222,9 +222,8 @@ var ReactCompositeComponent = {
}
var propsMutated = inst.props !== publicProps;
var componentName = Component.displayName ||
Component.name ||
'Component';
var componentName =
Component.displayName || Component.name || 'Component';
warning(
inst.props === undefined || !propsMutated,
@ -300,11 +299,30 @@ var ReactCompositeComponent = {
'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?',
this.getName() || 'A component',
);
if (
isPureComponent(Component) &&
typeof inst.shouldComponentUpdate !== 'undefined'
) {
warning(
false,
'%s has a method called shouldComponentUpdate(). ' +
'shouldComponentUpdate should not be used when extending React.PureComponent. ' +
'Please extend React.Component if shouldComponentUpdate is used.',
this.getName() || 'A pure component',
);
}
warning(
!inst.defaultProps,
'Setting defaultProps as an instance property on %s is not supported and will be ignored.' +
' Instead, define defaultProps as a static property on %s.',
this.getName() || 'a component',
this.getName() || 'a component',
);
}
var initialState = inst.state;
if (initialState === undefined) {
inst.state = (initialState = null);
inst.state = initialState = null;
}
invariant(
typeof initialState === 'object' && !Array.isArray(initialState),
@ -730,7 +748,13 @@ var ReactCompositeComponent = {
_checkContextTypes: function(typeSpecs, values, location: string) {
if (__DEV__) {
ReactDebugCurrentFrame.current = this._debugID;
checkReactTypeSpec(typeSpecs, values, location, this.getName());
checkPropTypes(
typeSpecs,
values,
location,
this.getName(),
ReactDebugCurrentFrame.getStackAddendum,
);
ReactDebugCurrentFrame.current = null;
}
},
@ -892,7 +916,8 @@ var ReactCompositeComponent = {
}
} else {
if (this._compositeType === ReactCompositeComponentTypes.PureClass) {
shouldUpdate = !shallowEqual(prevProps, nextProps) ||
shouldUpdate =
!shallowEqual(prevProps, nextProps) ||
!shallowEqual(inst.state, nextState);
}
}
@ -998,11 +1023,9 @@ var ReactCompositeComponent = {
var hasComponentDidUpdate = !!inst.componentDidUpdate;
var prevProps;
var prevState;
var prevContext;
if (hasComponentDidUpdate) {
prevProps = inst.props;
prevState = inst.state;
prevContext = inst.context;
}
if (inst.componentWillUpdate) {
@ -1036,12 +1059,7 @@ var ReactCompositeComponent = {
if (__DEV__) {
transaction.getReactMountReady().enqueue(() => {
measureLifeCyclePerf(
inst.componentDidUpdate.bind(
inst,
prevProps,
prevState,
prevContext,
),
inst.componentDidUpdate.bind(inst, prevProps, prevState),
this._debugID,
'componentDidUpdate',
);
@ -1050,12 +1068,7 @@ var ReactCompositeComponent = {
transaction
.getReactMountReady()
.enqueue(
inst.componentDidUpdate.bind(
inst,
prevProps,
prevState,
prevContext,
),
inst.componentDidUpdate.bind(inst, prevProps, prevState),
inst,
);
}
@ -1303,11 +1316,13 @@ var ReactCompositeComponent = {
getName: function() {
var type = this._currentElement.type;
var constructor = this._instance && this._instance.constructor;
return type.displayName ||
return (
type.displayName ||
(constructor && constructor.displayName) ||
type.name ||
(constructor && constructor.name) ||
null;
null
);
},
/**

Просмотреть файл

@ -15,12 +15,12 @@ var ReactComponentEnvironment = require('ReactComponentEnvironment');
var ReactInstanceMap = require('ReactInstanceMap');
var ReactInstrumentation = require('ReactInstrumentation');
var ReactCurrentOwner = require('react/lib/ReactCurrentOwner');
var ReactReconciler = require('ReactReconciler');
var ReactChildReconciler = require('ReactChildReconciler');
var {ReactCurrentOwner} = require('ReactGlobalSharedState');
var emptyFunction = require('fbjs/lib/emptyFunction');
var flattenChildren = require('flattenChildren');
var flattenStackChildren = require('flattenStackChildren');
var invariant = require('fbjs/lib/invariant');
/**
@ -212,7 +212,7 @@ var ReactMultiChild = {
if (this._currentElement) {
try {
ReactCurrentOwner.current = this._currentElement._owner;
nextChildren = flattenChildren(
nextChildren = flattenStackChildren(
nextNestedChildrenElements,
selfDebugID,
);
@ -233,7 +233,10 @@ var ReactMultiChild = {
return nextChildren;
}
}
nextChildren = flattenChildren(nextNestedChildrenElements, selfDebugID);
nextChildren = flattenStackChildren(
nextNestedChildrenElements,
selfDebugID,
);
ReactChildReconciler.updateChildren(
prevChildren,
nextChildren,

Просмотреть файл

@ -21,7 +21,7 @@ var ReactRef = {};
if (__DEV__) {
var ReactCompositeComponentTypes = require('ReactCompositeComponentTypes');
var ReactComponentTreeHook = require('react/lib/ReactComponentTreeHook');
var {ReactComponentTreeHook} = require('ReactGlobalSharedState');
var warning = require('fbjs/lib/warning');
var warnedAboutStatelessRefs = {};
@ -47,9 +47,8 @@ function attachRef(ref, component, owner) {
let warningKey = ownerName || component._debugID;
let element = component._currentElement;
if (element && element._source) {
warningKey = element._source.fileName +
':' +
element._source.lineNumber;
warningKey =
element._source.fileName + ':' + element._source.lineNumber;
}
if (!warnedAboutStatelessRefs[warningKey]) {
warnedAboutStatelessRefs[warningKey] = true;
@ -124,9 +123,11 @@ ReactRef.shouldUpdateRefs = function(
nextOwner = nextElement._owner;
}
return prevRef !== nextRef ||
return (
prevRef !== nextRef ||
// If owner changes but we have an unchanged function ref, don't update refs
(typeof nextRef === 'string' && nextOwner !== prevOwner);
(typeof nextRef === 'string' && nextOwner !== prevOwner)
);
};
ReactRef.detachRefs = function(

Просмотреть файл

@ -11,10 +11,10 @@
'use strict';
var ReactCurrentOwner = require('react/lib/ReactCurrentOwner');
var ReactInstanceMap = require('ReactInstanceMap');
var ReactInstrumentation = require('ReactInstrumentation');
var ReactUpdates = require('ReactUpdates');
var {ReactCurrentOwner} = require('ReactGlobalSharedState');
if (__DEV__) {
var warning = require('fbjs/lib/warning');
@ -226,7 +226,8 @@ var ReactUpdateQueue = {
return;
}
var queue = internalInstance._pendingStateQueue ||
var queue =
internalInstance._pendingStateQueue ||
(internalInstance._pendingStateQueue = []);
queue.push(partialState);

Просмотреть файл

@ -124,14 +124,16 @@ var TransactionImpl = {
*
* @return {*} Return value from `method`.
*/
perform: function<A, B, C, D, E, F, G, T: (
a: A,
b: B,
c: C,
d: D,
e: E,
f: F,
) => G>(method: T, scope: any, a: A, b: B, c: C, d: D, e: E, f: F): G {
perform: function<
A,
B,
C,
D,
E,
F,
G,
T: (a: A, b: B, c: C, d: D, e: E, f: F) => G
>(method: T, scope: any, a: A, b: B, c: C, d: D, e: E, f: F): G {
invariant(
!this.isInTransaction(),
'Transaction.perform(...): Cannot initialize a transaction when there ' +

Просмотреть файл

@ -6,14 +6,14 @@
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule flattenChildren
* @providesModule flattenStackChildren
* @flow
*/
'use strict';
var KeyEscapeUtils = require('KeyEscapeUtils');
var traverseAllChildren = require('traverseAllChildren');
var traverseStackChildren = require('traverseStackChildren');
var warning = require('fbjs/lib/warning');
var ReactComponentTreeHook;
@ -28,7 +28,8 @@ if (
// https://github.com/facebook/react/issues/7240
// Remove the inline requires when we don't need them anymore:
// https://github.com/facebook/react/pull/7178
ReactComponentTreeHook = require('react/lib/ReactComponentTreeHook');
ReactComponentTreeHook = require('ReactGlobalSharedState')
.ReactComponentTreeHook;
}
/**
@ -49,7 +50,8 @@ function flattenSingleChildIntoContext(
const keyUnique = result[name] === undefined;
if (__DEV__) {
if (!ReactComponentTreeHook) {
ReactComponentTreeHook = require('react/lib/ReactComponentTreeHook');
ReactComponentTreeHook = require('ReactGlobalSharedState')
.ReactComponentTreeHook;
}
if (!keyUnique) {
warning(
@ -73,7 +75,7 @@ function flattenSingleChildIntoContext(
* children will not be included in the resulting object.
* @return {!object} flattened children keyed by name.
*/
function flattenChildren(
function flattenStackChildren(
children: ReactElement<any>,
selfDebugID?: number,
): ?{[name: string]: ReactElement<any>} {
@ -83,7 +85,7 @@ function flattenChildren(
var result = {};
if (__DEV__) {
traverseAllChildren(
traverseStackChildren(
children,
(traverseContext, child, name) =>
flattenSingleChildIntoContext(
@ -95,9 +97,9 @@ function flattenChildren(
result,
);
} else {
traverseAllChildren(children, flattenSingleChildIntoContext, result);
traverseStackChildren(children, flattenSingleChildIntoContext, result);
}
return result;
}
module.exports = flattenChildren;
module.exports = flattenStackChildren;

Просмотреть файл

@ -42,10 +42,12 @@ function getDeclarationErrorAddendum(owner) {
* @return {boolean} Returns true if this is a valid internal type.
*/
function isInternalComponentType(type) {
return typeof type === 'function' &&
return (
typeof type === 'function' &&
typeof type.prototype !== 'undefined' &&
typeof type.prototype.mountComponent === 'function' &&
typeof type.prototype.receiveComponent === 'function';
typeof type.prototype.receiveComponent === 'function'
);
}
/**
@ -73,7 +75,8 @@ function instantiateReactComponent(node, shouldHaveDebugID) {
type !== null &&
Object.keys(type).length === 0)
) {
info += ' You likely forgot to export your component from the file ' +
info +=
' You likely forgot to export your component from the file ' +
"it's defined in.";
}
}

Просмотреть файл

@ -6,12 +6,11 @@
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule traverseAllChildren
* @providesModule traverseStackChildren
*/
'use strict';
var ReactCurrentOwner = require('react/lib/ReactCurrentOwner');
var REACT_ELEMENT_TYPE = require('ReactElementSymbol');
var getIteratorFn = require('getIteratorFn');
@ -19,6 +18,12 @@ var invariant = require('fbjs/lib/invariant');
var KeyEscapeUtils = require('KeyEscapeUtils');
var warning = require('fbjs/lib/warning');
if (__DEV__) {
var {
getCurrentStackAddendum,
} = require('ReactGlobalSharedState').ReactComponentTreeHook;
}
var SEPARATOR = '.';
var SUBSEPARATOR = ':';
@ -61,7 +66,7 @@ function getComponentKey(component, index) {
* process.
* @return {!number} The number of children in this subtree.
*/
function traverseAllChildrenImpl(
function traverseStackChildrenImpl(
children,
nameSoFar,
callback,
@ -101,7 +106,7 @@ function traverseAllChildrenImpl(
for (var i = 0; i < children.length; i++) {
child = children[i];
nextName = nextNamePrefix + getComponentKey(child, i);
subtreeCount += traverseAllChildrenImpl(
subtreeCount += traverseStackChildrenImpl(
child,
nextName,
callback,
@ -114,21 +119,12 @@ function traverseAllChildrenImpl(
if (__DEV__) {
// Warn about using Maps as children
if (iteratorFn === children.entries) {
let mapsAsChildrenAddendum = '';
if (ReactCurrentOwner.current) {
var mapsAsChildrenOwnerName = ReactCurrentOwner.current.getName();
if (mapsAsChildrenOwnerName) {
mapsAsChildrenAddendum = '\n\nCheck the render method of `' +
mapsAsChildrenOwnerName +
'`.';
}
}
warning(
didWarnAboutMaps,
'Using Maps as children is unsupported and will likely yield ' +
'unexpected results. Convert it to a sequence/iterable of keyed ' +
'ReactElements instead.%s',
mapsAsChildrenAddendum,
getCurrentStackAddendum(),
);
didWarnAboutMaps = true;
}
@ -140,7 +136,7 @@ function traverseAllChildrenImpl(
while (!(step = iterator.next()).done) {
child = step.value;
nextName = nextNamePrefix + getComponentKey(child, ii++);
subtreeCount += traverseAllChildrenImpl(
subtreeCount += traverseStackChildrenImpl(
child,
nextName,
callback,
@ -150,14 +146,10 @@ function traverseAllChildrenImpl(
} else if (type === 'object') {
var addendum = '';
if (__DEV__) {
addendum = ' If you meant to render a collection of children, use an array ' +
'instead.';
if (ReactCurrentOwner.current) {
var name = ReactCurrentOwner.current.getName();
if (name) {
addendum += '\n\nCheck the render method of `' + name + '`.';
}
}
addendum =
' If you meant to render a collection of children, use an array ' +
'instead.' +
getCurrentStackAddendum();
}
var childrenString = '' + children;
invariant(
@ -178,8 +170,8 @@ function traverseAllChildrenImpl(
* Traverses children that are typically specified as `props.children`, but
* might also be specified through attributes:
*
* - `traverseAllChildren(this.props.children, ...)`
* - `traverseAllChildren(this.props.leftPanelChildren, ...)`
* - `traverseStackChildren(this.props.children, ...)`
* - `traverseStackChildren(this.props.leftPanelChildren, ...)`
*
* The `traverseContext` is an optional argument that is passed through the
* entire traversal. It can be used to store accumulations or anything else that
@ -190,12 +182,12 @@ function traverseAllChildrenImpl(
* @param {?*} traverseContext Context for traversal.
* @return {!number} The number of children in this subtree.
*/
function traverseAllChildren(children, callback, traverseContext) {
function traverseStackChildren(children, callback, traverseContext) {
if (children == null) {
return 0;
}
return traverseAllChildrenImpl(children, '', callback, traverseContext);
return traverseStackChildrenImpl(children, '', callback, traverseContext);
}
module.exports = traverseAllChildren;
module.exports = traverseStackChildren;

Просмотреть файл

@ -76,15 +76,6 @@ let rethrowCaughtError = function() {
}
};
/**
* Call a function while guarding against errors that happens within it.
* Returns an error if it throws, otherwise null.
*
* @param {String} name of the guard to use for logging or debugging
* @param {Function} func The function to invoke
* @param {*} context The context to use when calling the function
* @param {...*} args Arguments for function
*/
const ReactErrorUtils = {
injection: {
injectErrorUtils(injectedErrorUtils: Object) {
@ -96,6 +87,15 @@ const ReactErrorUtils = {
},
},
/**
* Call a function while guarding against errors that happens within it.
* Returns an error if it throws, otherwise null.
*
* @param {String} name of the guard to use for logging or debugging
* @param {Function} func The function to invoke
* @param {*} context The context to use when calling the function
* @param {...*} args Arguments for function
*/
invokeGuardedCallback: function<A, B, C, D, E, F, Context>(
name: string | null,
func: (a: A, b: B, c: C, d: D, e: E, f: F) => void,

Просмотреть файл

@ -19,6 +19,7 @@ var ReactFeatureFlags = {
logTopLevelRenders: false,
prepareNewChildrenBeforeUnmountInStack: true,
disableNewFiberFeatures: false,
enableAsyncSubtreeAPI: false,
};
module.exports = ReactFeatureFlags;

Просмотреть файл

@ -28,7 +28,8 @@ function adler32(data: string): number {
while (i < m) {
var n = Math.min(i + 4096, m);
for (; i < n; i += 4) {
b += (a += data.charCodeAt(i)) +
b +=
(a += data.charCodeAt(i)) +
(a += data.charCodeAt(i + 1)) +
(a += data.charCodeAt(i + 2)) +
(a += data.charCodeAt(i + 3));
@ -37,11 +38,11 @@ function adler32(data: string): number {
b %= MOD;
}
for (; i < l; i++) {
b += (a += data.charCodeAt(i));
b += a += data.charCodeAt(i);
}
a %= MOD;
b %= MOD;
return a | b << 16;
return a | (b << 16);
}
module.exports = adler32;

Просмотреть файл

@ -24,7 +24,8 @@ var getComponentName = require('getComponentName');
import type {Fiber} from 'ReactFiber';
function describeComponentFrame(name, source: any, ownerName) {
return '\n in ' +
return (
'\n in ' +
(name || 'Unknown') +
(source
? ' (at ' +
@ -32,7 +33,8 @@ function describeComponentFrame(name, source: any, ownerName) {
':' +
source.lineNumber +
')'
: ownerName ? ' (created by ' + ownerName + ')' : '');
: ownerName ? ' (created by ' + ownerName + ')' : '')
);
}
function describeFiber(fiber: Fiber): string {

Просмотреть файл

@ -1,26 +0,0 @@
/**
* Copyright 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule checkReactTypeSpec
*/
'use strict';
var checkPropTypes = require('react/lib/checkPropTypes');
var {getStackAddendum} = require('react/lib/ReactDebugCurrentFrame');
function checkReactTypeSpec(
typeSpecs,
values,
location: string,
componentName,
) {
checkPropTypes(typeSpecs, values, location, componentName, getStackAddendum);
}
module.exports = checkReactTypeSpec;

Просмотреть файл

@ -95,7 +95,7 @@ var addPoolingTo = function<T>(
CopyConstructor: Class<T>,
pooler: Pooler,
): Class<T> & {
getPooled /* arguments of the constructor */(): T,
getPooled(): /* arguments of the constructor */ T,
release(): void,
} {
// Casting as any so that flow ignores the actual implementation and trusts

Просмотреть файл

@ -14,9 +14,8 @@
// The Symbol used to tag the ReactElement type. If there is no native Symbol
// nor polyfill, then a plain number is used for performance.
var REACT_ELEMENT_TYPE = (typeof Symbol === 'function' &&
Symbol.for &&
Symbol.for('react.element')) ||
var REACT_ELEMENT_TYPE =
(typeof Symbol === 'function' && Symbol.for && Symbol.for('react.element')) ||
0xeac7;
module.exports = REACT_ELEMENT_TYPE;

Просмотреть файл

@ -6,8 +6,8 @@
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @flow
* @providesModule getComponentName
* @flow
*/
'use strict';

Просмотреть файл

@ -31,7 +31,8 @@ var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec.
* @return {?function}
*/
function getIteratorFn(maybeIterable: ?any): ?() => ?Iterator<*> {
var iteratorFn = maybeIterable &&
var iteratorFn =
maybeIterable &&
((ITERATOR_SYMBOL && maybeIterable[ITERATOR_SYMBOL]) ||
maybeIterable[FAUX_ITERATOR_SYMBOL]);
if (typeof iteratorFn === 'function') {

Просмотреть файл

@ -20,7 +20,8 @@
function reactProdInvariant(code: string): void {
var argCount = arguments.length - 1;
var message = 'Minified React error #' +
var message =
'Minified React error #' +
code +
'; visit ' +
'http://facebook.github.io/react/docs/error-decoder.html?invariant=' +
@ -30,7 +31,8 @@ function reactProdInvariant(code: string): void {
message += '&args[]=' + encodeURIComponent(arguments[argIdx + 1]);
}
message += ' for the full message or use the non-minified dev environment' +
message +=
' for the full message or use the non-minified dev environment' +
' for full errors and additional helpful warnings.';
var error: Error & {framesToPop?: number} = new Error(message);

2
Libraries/react-native/React.js поставляемый
Просмотреть файл

@ -11,4 +11,4 @@
'use strict';
module.exports = require('react/lib/React');
module.exports = require('react');

Просмотреть файл

@ -128,7 +128,7 @@
"react-native": "local-cli/wrong-react-native.js"
},
"peerDependencies": {
"react": "16.0.0-alpha.6"
"react": "16.0.0-alpha.12"
},
"dependencies": {
"absolute-path": "^0.0.0",
@ -162,7 +162,7 @@
"denodeify": "^1.2.1",
"errno": ">=0.1.1 <0.2.0-0",
"event-target-shim": "^1.0.5",
"fbjs": "~0.8.9",
"fbjs": "0.8.12",
"fbjs-scripts": "^0.7.0",
"form-data": "^2.1.1",
"fs-extra": "^1.0.0",
@ -227,8 +227,8 @@
"jest-repl": "19.0.2",
"jest-runtime": "^19.0.3",
"mock-fs": "^3.11.0",
"react": "16.0.0-alpha.6",
"react-test-renderer": "16.0.0-alpha.6",
"react": "16.0.0-alpha.12",
"react-test-renderer": "16.0.0-alpha.12",
"shelljs": "0.6.0",
"sinon": "^2.0.0-pre.2"
}